puppeteer實戰系列-網頁性能分析(三)

前兩篇文章中,咱們講了安裝和截圖,這篇咱們來說講頁面性能分析的相關體系。git

衆所周知,頁面性能優化要講起來可謂是整大條鏈路上的事情,在這裏筆者將不開展描述,後續筆者會出個全面的性能優化系列文章再進行講解。回到咱們的正題,咱們是利用 puppeteer 對頁面進行性能數據採集並分析,達到一個性能監控的效果。github

這裏筆者是用的 Web performance 收集的,畢竟是原生對吧。 GoogleChrome 推的 lighthouse 也是個不錯的工具,感興趣的同窗可自行研究 傳送門web

固然了,我們要分析的頁面在這裏不是咱自家產的,假如是自家頁面,那咱們只須要將代碼包裝成sdk,用戶訪問的時候收集真實數據,再分析便可。因此這裏主要是模擬分析第三方的頁面。在講具體操做前,咱們先來認識一下 performance,看下圖緩存

相關時間點在 timing 裏,加載的資源列表在 getEntries 裏,筆者也是根據下面這張圖來歸結相關時間節點數據的,有不對的地方同窗們幫忙指正下性能優化

因此有了下面核心代碼服務器

function performance() {
  const data = {
    cache: ['domainLookupStart', 'fetchStart'], // 讀取緩存時間
    dns: ['domainLookupEnd', 'domainLookupStart'], // DNS 解析耗時
    tcp: ['connectEnd', 'connectStart'], // TCP 鏈接耗時
    req: ['responseStart', 'requestStart'], // 網絡請求耗時
    res: ['responseEnd', 'responseStart'], // 數據傳輸耗時
    dom: ['domContentLoadedEventStart', 'domLoading'], // DOM 解析耗時
    readycb: ['domContentLoadedEventEnd', 'domContentLoadedEventStart'], // domContentLoaded回調函數耗時
    fasrt: ['domComplete', 'domContentLoadedEventEnd'], // 首屏異步資源加載耗時,即domContentLoaded和load之間加載的資源,通常爲圖片加載,JS異步加載的資源
    loadcb: ['loadEventEnd', 'loadEventStart'], // load回調函數耗時
    ready: ['domContentLoadedEventEnd', 'fetchStart'], // DOM Ready耗時,白屏時間
    load: ['loadEventEnd', 'fetchStart'] // 頁面徹底加載時間
  };
  const getData = {};
  const performance = window.performance || window.msPerformance || window.webkitPerformance;
  if (!performance || !performance.timing) {
    return null;
  }
  const timing = performance.timing;
  Object.keys(data).map(item => {
    const firstParams = timing[data[item][0]];
    const secondParams = timing[data[item][1]];
    const value = Math.round(firstParams - secondParams);
    value >= 0 && value < 36e5 && (getData[item] = value);
  });
  getData.resourceList = performance.getEntries();
  return getData;
}
複製代碼

因此當咱們加載第三方頁面的時候,咱們插入此腳本,把數據撈出來,下面舉個🌰網絡

const browser = await puppeteer.launch({
  headless: true,
  args: [ '--no-sandbox', '--disable-setuid-sandbox' ],
});
const page = await browser.newPage();
await page.goto('https://juejin.im', {
  waitUntil: [ 'load' ]
});
const monitorData = await page.evaluate(() => {
  // 這裏就拿咱們最多見也最關心的數據,更全的看上面核心代碼圖便可
  const data = {
    ready: [ 'domContentLoadedEventEnd', 'fetchStart' ], // DOM Ready耗時,白屏時間
    load: [ 'loadEventEnd', 'fetchStart' ] // 頁面徹底加載時間
  };
  const getData = {};
  const performance = window.performance || window.msPerformance || window.webkitPerformance;
  const timing = performance.timing;
  Object.keys(data).map(item => {
    const firstParams = timing[data[item][0]];
    const secondParams = timing[data[item][1]];
    const value = Math.round(firstParams - secondParams);
    value >= 0 && value < 36e5 && (getData[item] = value);
  });
  getData.resourceList = performance.getEntries();
  return Promise.resolve(getData);
});

console.log(monitorData);
複製代碼

拿到這些數據後,就能夠開展各自的業務的場景了,好比後臺系統上的展現監控,釘釘報警優化等等。 再複雜一點的場景可能須要模擬網絡環境,咱們須要再添加一些代碼,以下:less

const NETWORK_PRESETS = {
  // 全部速度 / 8 是由於網絡速度一般以比特/秒,而 DevTools 預計吞吐量在字節/秒! (1字節 = 8比特)
  GPRS: {
    offline: false, // 是否鏈接
    downloadThroughput: (50 * 1024) / 8, // 模擬下載速度
    uploadThroughput: (20 * 1024) / 8,  // 模擬上傳速度 
    latency: 500 // 模擬延遲(毫秒)
  },
  Regular2G: {
    offline: false,
    downloadThroughput: (250 * 1024) / 8,
    uploadThroughput: (50 * 1024) / 8,
    latency: 300
  },
  Good2G: {
    offline: false,
    downloadThroughput: (450 * 1024) / 8,
    uploadThroughput: (150 * 1024) / 8,
    latency: 150
  },
  Regular3G: {
    offline: false,
    downloadThroughput: (750 * 1024) / 8,
    uploadThroughput: (250 * 1024) / 8,
    latency: 100
  },
  Good3G: {
    offline: false,
    downloadThroughput: (1.5 * 1024 * 1024) / 8,
    uploadThroughput: (750 * 1024) / 8,
    latency: 40
  },
  Regular4G: {
    offline: false,
    downloadThroughput: (4 * 1024 * 1024) / 8,
    uploadThroughput: (3 * 1024 * 1024) / 8,
    latency: 20
  },
  DSL: {
    offline: false,
    downloadThroughput: (2 * 1024 * 1024) / 8,
    uploadThroughput: (1 * 1024 * 1024) / 8,
    latency: 5
  },
  WiFi: {
    offline: false,
    downloadThroughput: (30 * 1024 * 1024) / 8,
    uploadThroughput: (15 * 1024 * 1024) / 8,
    latency: 2
  }
};

async function start(url, network) {
  const browser = await puppeteer.launch({
    headless: true,
    args: [ '--no-sandbox', '--disable-setuid-sandbox' ],
  });
  const page = await browser.newPage();
  await page.goto(url, { waitUntil: [ 'load' ]});

  // 添加網絡環境
  if (network !== 'default') {
    // Connect to Chrome DevTools
    const client = await page.target().createCDPSession();
    // Set throttling property
    await client.send('Network.emulateNetworkConditions', NETWORK_PRESETS[network]);
  }

  const monitorData = await page.evaluate(() => {
    // ...同上
  });

  console.log(monitorData);
}

複製代碼

總結

window.performance.getEntries() 的方式拿到的資源,不是本域下面的話,通常是拿不到資源大小的,這個是由第三方cdn或者服務器所控制的。lighthouse 是拿獲得的,因此根據各自場景,結合起來使用也是沒問題的。另外 puppeteer 自己也提供一些頁面數據在 page.metrics() 方法裏,同窗們可自行查看。最後,有其餘好工具分享的,歡迎評論區留言😯~_~dom

相關文章
相關標籤/搜索