網頁性能、錯誤監控

一、Javascript組成包括如下3個部分:javascript

ECMAScript(核心) 描述了JS的語法和基本對象。
文檔對象模型 (DOM) 處理網頁內容的方法和接口
瀏覽器對象模型(BOM) 與瀏覽器交互的方法和接口

(1) DOM 是 W3C 的標準; [全部瀏覽器公共遵照的標準]
(2) BOM 是 各個瀏覽器廠商根據 DOM在各自瀏覽器上的實現;[表現爲不一樣瀏覽器定義有差異,實現方式不一樣]
(3) window 是 BOM 對象,而非 js 對象;javacsript是經過訪問BOM(Browser Object Model)對象來訪問、控制、修改客戶端(瀏覽器)css

如圖所示(截圖W3CSchool目錄):
imagejava

二、DOM事件流包括三個階段
(1). 事件捕獲階段 : 當事件發生時,首先發生的是事件捕獲,爲父元素截獲事件提供了機會。它認爲當某個事件發生時,父元素應該更早接收到事件,具體元素則最後接收到事件。
(2). 處於目標階段 : 事件到了具體元素時,在具體元素上發生,而且被當作冒泡階段的一部分。隨後,冒泡階段發生,事件開始冒泡,而後逐級傳播到較爲不具體的節點。
(3). 事件冒泡階段 : 事件冒泡過程,是能夠被阻止的。防止事件冒泡而帶來沒必要要的錯誤和困擾。這個方法就是: stopPropagation()segmentfault

固然,因爲時代更迭,事件冒泡方式更勝一籌。因此放心的使用事件冒泡,有特殊須要再使用事件捕獲便可。跨域

<div id="test">
    <button onclick="alert(22)">DOM事件流</button>
</div>

var el = document.getElementById('test')
el.addEventListener('click', function (e) {
   alert(11)
}, true)
el.addEventListener('click', function (e) {
   alert(33)
}, false)

運行結果:網頁前後三次彈出警示框,順序爲:11 --> 22 --> 33

如圖所示(圖片源於網絡,若侵權請告知):
imagepromise

三、網頁性能參數 performance API瀏覽器

如圖所示(圖片源於網絡,若侵權請告知):
瀏覽器核心工做軸緩存

四、網頁錯誤監控
window.onerror是一個全局變量,默認值爲null。當有js運行時錯誤觸發時,window會觸發error事件。
addEventListener('error')監聽js運行時錯誤事件,會比window.onerror先觸發,與onerror的功能大致相似,不一樣的是它還能夠能夠全局捕獲資源(如img,css...)加載異常的錯誤。服務器

五、網頁性能、錯誤監控代碼
網頁代碼:網絡

<head>
    <script src="./monitor.js"></script>
</head>
<body>
    <button onclick="throw new Error({message: '手動拋出錯誤1'})">錯誤測試按鈕1</button>
    <button onclick="Promise.reject('promise error')">錯誤測試按鈕2</button>
    <button onclick="throw('手動拋出錯誤2')">錯誤測試按鈕3</button>
</body>

monitor.js: 需放到head標籤先於可能拋錯誤代碼執行

// 保存監控信息
let monitor = {
    performance: {}, // 性能監控
    resources: {}, // 資源監控
    errors: [], // 錯誤監控

    user: {
        // Screen 對象包含有關客戶端顯示屏幕的信息。
        screen: screen.width, // 屏幕的總寬度
        height: screen.height,
        // Navigator 對象包含有關瀏覽器的信息
        platform: navigator.platform, // 運行瀏覽器的操做系統
        userAgent: navigator.userAgent, // 瀏覽器用於 HTTP 請求的UA頭的值
        language: navigator.language // 瀏覽器 UI 的語言
    }
}

// 性能監控
const getPerformance = () => {
    if (!window.performance) return
    const timing = window.performance.timing
    const performance = {
        redirect: timing.redirectEnd - timing.redirectStart, // 最後一個HTTP重定向完成時 - 第一個HTTP重定向開始時
        whiteScreen: timing.domLoading - timing.navigationStart, // 當前網頁DOM結構開始解析時 - 上一個文檔卸載(unload)結束時
        dom: timing.domComplete - timing.domLoading, // 當前文檔解析完成 - 當前網頁DOM結構開始解析時
        load: timing.loadEventEnd - timing.navigationStart, // 加載事件完成時 - 上一個文檔卸載(unload)結束時
        unload: timing.unloadEventEnd - timing.unloadEventStart, // unload事件處理完成時 - unload事件拋出時
        request: timing.responseEnd - timing.requestStart, // 瀏覽器從服務器收到(或從本地緩存讀取,或從本地資源讀取)最後一個字節時 - 瀏覽器向服務器發出HTTP請求時(或開始讀取本地緩存時)
        time: new Date().getTime()
    }
    return performance
}

// 資源監控
const getResources = () => {
    if (!window.performance) return
    const data = window.performance.getEntriesByType('resource')
    const resource = {
        xmlhttprequest: [],
        css: [],
        other: [],
        script: [],
        img: [],
        link: [],
        fetch: [],

        time: new Date().getTime()
    }
    data.forEach(item => {
        const arr = resource[item.initiatorType]
        arr && arr.push({
            name: item.name, // 資源URL
            duration: item.duration.toFixed(2), // fetch資源耗時
            size: item.transferSize, // fetch獲取資源的大小,遇到本地緩存資源或跨域資源時返回0
            protocol: item.nextHopProtocol // 獲取資源的網絡協議
        })
    })
    return resource
}


// 錯誤監控
addEventListener('error', e => {
    const target = e.target
    console.log(target);
    
    if (target != window) {
        monitor.errors.push({
            type: target.localName,
            url: target.src || target.href,
            msg: (target.src || target.href) + 'is load error',

            time: new Date().getTime()
        })
    }

    console.log('全部的錯誤信息--捕獲JS執行時錯誤、資源加載錯誤');
    console.log(monitor.errors);
}, true)

window.onerror =  function (msg, url, row, col, error) {
    monitor.errors.push({
        type: 'javascript',
        row: row,
        col: col,
        msg: error && error.stack ? error.stack : msg,
        url: url,

        time: new Date().getTime()
    })

    console.log('全部的錯誤信息--捕獲JS執行時錯誤');
    console.log(monitor.errors);
}

addEventListener('unhandledrejection', e => {
    monitor.errors.push({
        type: 'promise',
        msg: (e.reason && e.reason.msg) || e.reason || '',

        time: new Date().getTime()
    })

    console.log('全部的錯誤信息--捕獲Promise異常未處理錯誤');
    console.log(monitor.errors);
})

window.onload = () => {
    if (window.requestIdleCallback) {
        // requestIdleCallback方法 將在瀏覽器的空閒時段內調用的函數排隊
        window.requestIdleCallback(() => { 
            monitor.performance = getPerformance()
            monitor.resources = getResources()
            console.log('頁面性能信息');
            console.log(monitor.performance)
            console.log('頁面資源信息');
            console.log(monitor.resources)
        })
    } else {
        setTimeout(() => {
            monitor.performance = getPerformance()
            monitor.resources = getResources()
            console.log('頁面性能信息');
            console.log(monitor.performance)
            console.log('頁面資源信息');
            console.log(monitor.resources)
        }, 0)
    }
}
相關文章
相關標籤/搜索