你的页面为何慢,Performance Timeline 简介

介绍

Performance timeline
w3c 有两个版本的规范,本文基于 第二版本 介绍。
工欲善其事,必先利其器。要想使页面更快,那么准确测量出性能数据也是很重要的。 咱们来看一下,在一个web页面的生命周期以内,咱们基于 Performance Timeline能够获得哪些性能指标。javascript

主要分为如下三大类:java

  • navigation-timing:navigation of the document
  • resource-timing:页面资源
  • user-timing:开发者自定义的一些监控, 主要是(mark 和 measure,下文会讲)

举个🌰, w3c 上的例子,我稍加改造 :web

<img id="image0" src="https://www.w3.org/Icons/w3c_main.png" />
<script> function init() { // see [[USER-TIMING-2]] performance.mark("startWork"); setTimeout(() => { performance.mark("endWork"); measurePerf(); }, 2000); } function measurePerf() { performance .getEntries() .map(entry => JSON.stringify(entry, null, 2)) .forEach(json => console.log(json)); } 复制代码

引入了一个 外部图片,
mark 能够理解为标记了一个时间点
getEntries 获得全部的性能数据,最后输出。
具体结果可看:chrome

{
  "name": "",
  "entryType": "navigation",
  "startTime": 0,
  "duration": 50.07500003557652,
}
 {
  "name": "https://www.w3.org/Icons/w3c_main.png",
  "entryType": "resource",
}
 {
  "name": "startWork",
  "entryType": "mark",
  "startTime": 49.990000028628856,
  "duration": 0
}
 {
  "name": "first-paint",
  "entryType": "paint",
  "startTime": 94.83499999623746,
  "duration": 0
}
 {
  "name": "first-contentful-paint",
  "entryType": "paint",
  "startTime": 94.83499999623746,
  "duration": 0
}
 {
  "name": "endWork",
  "entryType": "mark",
  "startTime": 2050.5150000099093,
  "duration": 0
}
复制代码

由此我就获得了页面上,当时的全部性能指标,包括navigation, resource, FP, FCP...等一些自定义的指标。json

ps:浏览器

  • FP:页面上第一个像素落点的时候
  • FCP: 页面上开始有内容绘制的时候

如今我想要过滤一下只要我本身 mark 的点,
可采用:getEntriesByType(mark)
只想要页面绘制相关的 fp,fcp,
采用 getEntriesByName('first-paint')bash

but,咱们获得的就只是当时获得的性能指标,假如后面又有 图片请求了呢,又有 js 请求了呢 🤣🤣。 咱们要一直 轮询咱们的 measurePerf 吗? 固然有新的解决方式。微信

PerformanceObserver

PerformanceObserver,是浏览器内部对Performance实现的观察者模式,即: 当有性能数据产生时,主动通知你。dom

这解决了咱们以前的问题:async

  • 重复轮训
  • 轮巡时不断判断,这个数据是新产生的,仍是之前的
  • 可能其余数据的消费者也须要操做数据

监测页面FP,FCP

如今能够:

// 定义一个观察者
const observer = new PerformanceObserver(list => {
    list.getEntries().forEach((entry) => {
        console.log('entry对象', entry);
    });
});
// 观察的类型
observer.observe({
    entryTypes: ['paint']
});
复制代码

关于 entryTypes, 能够取以下值:

  • frame:event-loop 时的每一帧
  • navigation:导航
  • resource:资源
  • mark: 打点,获得一个时间戳
  • measure:在两个点之间测量
  • paint:绘制
  • longtask(好像只有 chrome支持):任何在浏览器中执行超过 50 ms 的任务,都是 long task

关于 entry: 每一个事件类型的 entry 对象都不同。

navigation entry 对象里能拿到相关的数据有

这里完整地描述了一个 页面 呈现的完整流程。 拿到每一个时间点能够进行分析每一个区间的时间耗费。

let t = entry
console.log('DNS查询耗时 :' + (t.domainLookupEnd - t.domainLookupStart).toFixed(0))
console.log('TCP连接耗时 :' + (t.connectEnd - t.connectStart).toFixed(0))
console.log('request请求耗时 :' + (t.responseEnd - t.responseStart).toFixed(0))
console.log('解析dom树耗时 :' + (t.domComplete - t.domInteractive).toFixed(0))
console.log('白屏时间 :' + (t.responseStart - t.navigationStart).toFixed(0))
console.log('domready时间 :' + (t.domContentLoadedEventEnd - t.navigationStart).toFixed(0))
console.log('onload时间 :' + (t.loadEventEnd - t.navigationStart).toFixed(0))
复制代码

resource entry 对象里能拿到相关的数据有

image

这里道理和上面的 navigation 同样。

mark

这里打了四个点,用来标识两个任务的开始时间和结束时间,两个任务分别采用 Promise 推迟执行。doTask 模拟推迟行为。

const doTask = (ms) => new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve()
  }, ms);
})
async function run() {
  performance.mark("startTask1");
  await doTask(1000); // Some developer code
  performance.mark("endTask1");

  performance.mark("startTask2");
  await doTask(2000); // Some developer code
  performance.mark("endTask2");

  // Log them out
  const entries = performance.getEntriesByType("mark");
  for (const entry of entries) {
    console.table(entry.toJSON());
  }
}
run();
复制代码

分别获得四个点的时间。

image

measure

用于在两个 **点 (即上文提到的打点) ** 之间测量时间 举个 例子:须要测量一个 for 循环花费的时间。

const observer = new PerformanceObserver(list => {
  list.getEntries().forEach((entry) => {
    console.table(entry);
  });
});

observer.observe({
  entryTypes: ['measure']
});
performance.mark('cal-start');
// 模拟耗时任务
for(let i = 0; i < 10000; i ++) {

}
performance.mark('cal-end');
// 该 measure 的名字:my-cal
// measure 开始的时间点:cal-start
// measure 结束的时间点:cal-end
performance.measure('my-cal', 'cal-start', 'cal-end')
复制代码

image

longtask

这个 支持度 好像不高,chrome 亲测能够。 能够检测 应用里 任何在浏览器中执行超过 50 ms 的任务。

缘由来源还比较多:

  • 浏览器的render
  • 自身的js执行

好比上面得 实例, 咱们仅需加入一个须要的检测 的 entryType 既可。

observer.observe({
  entryTypes: ['measure', 'longtask']
});
复制代码

能够看到,Performance timeline 第二版本,相对之前仍是有很大改进的,咱们也有了更多的手段获得想要监控的数据。 EOF。

参考

w3c
mdn-Long_Tasks_API
mdn-Performance-measure

最后

若是喜欢本篇文章,能够关注的微信公众号,若是不嫌烦,还能够把它添加到桌面😀。

search.png

相关文章
相关标签/搜索