1. 程式人生 > >Nodejs中分析web前端性能(window.performance)

Nodejs中分析web前端性能(window.performance)

代碼 web interact 返回值 efault 延遲 tab 前端性能 veh

在nodejs中,通過puppeteer來獲取web頁面中的window.performance對象,從而分析頁面的性能。下面直接上代碼。

const puppeteer = require(‘puppeteer‘);
const path = require("path");

const logger=require("./log");
const log = logger.getPuppeteerRecordLogger() ;

/*
    啟動瀏覽器
*/ 
async function launchBrowser(){
    //啟動瀏覽器實例 [puppeteer.createBrowserFetcher([options])]
  let browser = await puppeteer.launch({
    // 若是手動下載的chromium需要指定chromium地址, 默認引用地址為 /項目目錄/node_modules/puppeteer/.local-chromium/
    //executablePath: ‘/Users/huqiyang/Documents/project/z/chromium/Chromium.app/Contents/MacOS/Chromium‘,
    //如果是訪問https頁面 此屬性會忽略https錯誤
    ignoreHTTPSErrors: true,
    // 關閉headless模式, 不會打開瀏覽器
    headless: true,
    //瀏覽器啟動參數 https://peter.sh/experiments/chromium-command-line-switches/   --timeout
    args:[‘--disk-cache-size=0‘,‘--disable-cache‘,‘--disable-infobars‘,‘--window-size=800,600‘,‘--ignore-certificate-errors‘,‘--enable-feaures‘],
    //是否為每個選項卡自動打開DevTools面板。 如果此選項為true,則headless選項將設置為false。
    devtools: false,
    //Defaults to 30000 (30 seconds). Pass 0 to disable timeout.
    timeout: 0
    //放慢puppeteer執行的動作,方便調試
    //slowMo: 250
  });
  return browser ;
}

async function saveHarlog(url,dirPath,filename){
    let homesite = url ;
    //保存的文件路徑
    let harFilePath = path.join(dirPath,filename) ;
    //處理URL
    if(!(url.startsWith(‘http://‘) || url.startsWith(‘https://‘))){
        url = "http://" + url ;
    }

  //打開瀏覽器
  let browser = await launchBrowser() ;

  //創建一個新頁面
  //let page = await browser.newPage();
  const page = (await browser.pages())[0];
  try{      
    await page.goto(url,{
            timeout:0
    });

    /*
        在page上下文中得到window.performance.timing
    */
      const timing = await page.evaluate( _ => {
      const {navigationStart,unloadEventStart,unloadEventEnd,
        redirectStart,redirectEnd,fetchStart,domainLookupStart,
        domainLookupEnd,connectStart,connectEnd,secureConnectionStart,
        requestStart,responseStart,responseEnd,domLoading,domInteractive,
        domContentLoadedEventStart,domContentLoadedEventEnd,domComplete,
        loadEventStart,loadEventEnd} = window.performance.timing;
      return ({navigationStart:navigationStart,
                        unloadEventStart:unloadEventStart,
                        unloadEventEnd:unloadEventEnd,
                        redirectStart:redirectStart,
                        redirectEnd:redirectEnd,
                        fetchStart:fetchStart,
                        domainLookupStart:domainLookupStart,
                        domainLookupEnd:domainLookupEnd,
                        connectStart:connectStart,
                        connectEnd:connectEnd,
                        secureConnectionStart:secureConnectionStart,
                        requestStart:requestStart,
                        responseStart:responseStart,
                        responseEnd:responseEnd,
                        domLoading:domLoading,
                        domInteractive:domInteractive,
                        domContentLoadedEventStart:domContentLoadedEventStart,
                        domContentLoadedEventEnd:domContentLoadedEventEnd,
                        domComplete:domComplete,
                        loadEventStart:loadEventStart,
                        loadEventEnd:loadEventEnd})
        })
        log.info(‘--->‘ + JSON.stringify(timing)) ;

    if(timing){
        //long 型的毫秒數。上一個文檔卸載(unload)結束時的UNIX時間戳。如果沒有上一個文檔,這個值會和fetchStart相同。
        let navigationStart  = timing.navigationStart ;
        //long 型的毫秒數.表征了unload事件拋出時的UNIX時間戳,如果沒有上一個文檔, 這個值會返回0
        let unloadEventStart  = timing.unloadEventStart ;
        //long 型的毫秒數,表征了unload事件處理完成時的UNIX時間戳。如果沒有上一個文檔, 這個值會返回0
        let unloadEventEnd  = timing.unloadEventEnd ;
        //long 型的毫秒數,表征了第一個HTTP重定向開始時的UNIX時間戳。如果沒有重定向,或者重定向中的一個不同源,這個值會返回0.
        let redirectStart   = timing.redirectStart  ;
        //long 型的毫秒數,表征了最後一個HTTP重定向完成時(也就是說是HTTP響應的最後一個比特直接被收到的時間)的UNIX時間戳。如果沒有重定向,或者重定向中的一個不同源,這個值會返回0.
        let redirectEnd  = timing.redirectEnd  ;
        //long 型的毫秒數,表征了瀏覽器準備好使用HTTP請求來獲取(fetch)文檔的UNIX時間戳。這個時間點會在檢查任何應用緩存之前。
        let fetchStart  = timing.fetchStart  ;
        //long 型的毫秒數,表征了域名查詢開始的UNIX時間戳。如果使用了持續連接(persistent connection),或者這個信息存儲到了緩存或者本地資源上,這個值將和fetchStart一致。
        let domainLookupStart  = timing.domainLookupStart  ;
        //long 型的毫秒數,表征了域名查詢結束的UNIX時間戳。如果使用了持續連接(persistent connection),或者這個信息存儲到了緩存或者本地資源上,這個值將和 fetchStart一致。
        let domainLookupEnd  = timing.domainLookupEnd  ;
        //long 型的毫秒數,返回HTTP請求開始向服務器發送時的Unix毫秒時間戳。如果使用持久連接(persistent connection),則返回值等同於fetchStart屬性的值。
        let connectStart   = timing.connectStart   ;
        //long 型的毫秒數,返回瀏覽器與服務器之間的連接建立時的Unix毫秒時間戳。如果建立的是持久連接,則返回值等同於fetchStart屬性的值。連接建立指的是所有握手和認證過程全部結束。
        let connectEnd   = timing.connectEnd   ;
        //long 型的毫秒數,返回瀏覽器與服務器開始安全鏈接的握手時的Unix毫秒時間戳。如果當前網頁不要求安全連接,則返回0
        let secureConnectionStart  = timing.secureConnectionStart    ;
        //long 型的毫秒數,返回瀏覽器向服務器發出HTTP請求時(或開始讀取本地緩存時)的Unix毫秒時間戳
        let requestStart   = timing.requestStart ;
        //long 型的毫秒數,返回瀏覽器從服務器收到(或從本地緩存讀取)第一個字節時的Unix毫秒時間戳。如果傳輸層在開始請求之後失敗並且連接被重開,該屬性將會被數制成新的請求的相對應的發起時間。
        let responseStart  = timing.responseStart  ;
        //long 型的毫秒數,返回瀏覽器從服務器收到(或從本地緩存讀取,或從本地資源讀取)最後一個字節時(如果在此之前HTTP連接已經關閉,則返回關閉時)的Unix毫秒時間戳。
        let responseEnd  = timing.responseEnd  ;
        //long 型的毫秒數,返回當前網頁DOM結構開始解析時(即Document.readyState屬性變為“loading”、相應的 readystatechange事件觸發時)的Unix毫秒時間戳。
        let domLoading  = timing.domLoading  ;
        //long 型的毫秒數,返回當前網頁DOM結構結束解析、開始加載內嵌資源時(即Document.readyState屬性變為“interactive”、相應的readystatechange事件觸發時)的Unix毫秒時間戳
        let domInteractive = timing.domInteractive  ;
        //ong 型的毫秒數,返回當解析器發送DOMContentLoaded 事件,即所有需要被執行的腳本已經被解析時的Unix毫秒時間戳
        let domContentLoadedEventStart = timing.domContentLoadedEventStart  ;
        //long 型的毫秒數,返回當所有需要立即執行的腳本已經被執行(不論執行順序)時的Unix毫秒時間戳
        let domContentLoadedEventEnd = timing.domContentLoadedEventEnd  ;
        //long 型的毫秒數,返回當前文檔解析完成,即Document.readyState 變為 ‘complete‘且相對應的readystatechange 被觸發時的Unix毫秒時間戳
        let domComplete = timing.domComplete  ;
        //long 型的毫秒數,返回該文檔下,load事件被發送時的Unix毫秒時間戳。如果這個事件還未被發送,它的值將會是0
        let loadEventStart = timing.loadEventStart  ;
        //long 型的毫秒數,返回當load事件結束,即加載事件完成時的Unix毫秒時間戳。如果這個事件還未被發送,或者尚未完成,它的值將會是0
        let loadEventEnd = timing.loadEventEnd  ;

        //呈現了如何導航到當前文檔的信息
        //let navigation = performance.navigation ;
    }   
  }catch(error){
    log.info(‘resovle error :‘ + url + ";  error message:" + error) ;
  }finally{
    if(browser){
        await browser.close();      
    }
  } 
}

exports.launchBrowser = launchBrowser;
exports.saveHarlog = saveHarlog;

指標說明

//@param t -> timing
async function getPerformanceTiming (t) { 
    if (!t) {
        log.info(‘not allow null‘);
        return;
    }
    var times = {};

    //【重要】頁面加載完成的時間
    //【原因】這幾乎代表了用戶等待頁面可用的時間
    times.loadPage = t.loadEventEnd - t.navigationStart;

    //【重要】解析 DOM 樹結構的時間
    //【原因】反省下你的 DOM 樹嵌套是不是太多了!
    times.domReady = t.domComplete - t.responseEnd;

    //【重要】重定向的時間
    //【原因】拒絕重定向!比如,http://example.com/ 就不該寫成 http://example.com
    times.redirect = t.redirectEnd - t.redirectStart;

    //【重要】DNS 查詢時間
    //【原因】DNS 預加載做了麽?頁面內是不是使用了太多不同的域名導致域名查詢的時間太長?
    // 可使用 HTML5 Prefetch 預查詢 DNS ,見:[HTML5 prefetch](http://segmentfault.com/a/1190000000633364)           
    times.lookupDomain = t.domainLookupEnd - t.domainLookupStart;

    //【重要】讀取頁面第一個字節的時間
    //【原因】這可以理解為用戶拿到你的資源占用的時間,加異地機房了麽,加CDN 處理了麽?加帶寬了麽?加 CPU 運算速度了麽?
    // TTFB 即 Time To First Byte 的意思
    // 維基百科:https://en.wikipedia.org/wiki/Time_To_First_Byte
    times.ttfb = t.responseStart - t.navigationStart;

    //【重要】內容加載完成的時間
    //【原因】頁面內容經過 gzip 壓縮了麽,靜態資源 css/js 等壓縮了麽?
    times.request = t.responseEnd - t.requestStart;

    //【重要】執行 onload 回調函數的時間
    //【原因】是否太多不必要的操作都放到 onload 回調函數裏執行了,考慮過延遲加載、按需加載的策略麽?
    times.loadEvent = t.loadEventEnd - t.loadEventStart;

    // DNS 緩存時間
    times.appcache = t.domainLookupStart - t.fetchStart;

    // 卸載頁面的時間
    times.unloadEvent = t.unloadEventEnd - t.unloadEventStart;

    // TCP 建立連接完成握手的時間
    times.connect = t.connectEnd - t.connectStart;

    return times;
}

Nodejs中分析web前端性能(window.performance)