本文首发于公众号:符合预期的CoyPanjavascript
首先贴一下参考文章的地址:html
最近这段时间,我在作h5的首屏加速相关的工做。首先须要搞清楚的问题就是:首屏加速,究竟是要加速什么? 答案可能很简单:加快网页的展示过程。不过再细想一下,网页快不快是针对用户而言的,那么什么样的速度会让用户感到快呢?或者说,哪些指标可以衡量用户所感知的"快"呢?web
我首先想到的衡量指标就是网页开始请求,到页面渲染完成展示在用户眼前,这中间的时间差。现代浏览器都提供了window.performance
的api,能够经过window.performance.timing.fetchStart
来获取网页开始请求时候的时间戳。页面渲染完成的时间点,能够在页面的业务逻辑中判断。我用这种打点方式统计了业务中某页面的首屏加载时长:npm
(上图中,横坐标是加载耗时,单位是毫秒。纵坐标是各个加载耗时对应的pv数)canvas
上图的数据中,pv总数为90316,首屏加载时长60分位值为:1394ms,90分位值为:2715ms。也就是说,60%的用户能在1394毫秒内看到完整的页面,90%的用户能在2715毫秒内看到完整页面。api
在测量首屏时长的时候,为了看到长尾数据的影响,通常会采用分位值的方式,平均数会用来做为参考,毕竟平均数在样本量不够大的状况下,受极大、极小值的影响比较大(好比我和马云平均年薪几个亿)。浏览器
上面的数据中,我只是简单的统计了页面总体的首屏耗时。但其实页面加载是一个很复杂的过程。在加载过程当中,哪些指标可能会影响到用户的体验呢?谷歌给出了如下的指标:缓存
FP:首次绘制。用于标记导航以后浏览器在屏幕上渲染像素的时间点。这个不难理解,就是浏览器开始请求网页到网页首帧绘制的时间点。这个指标代表了网页请求是否成功。性能
FCP:首次内容绘制。FCP 标记的是浏览器渲染来自 DOM 第一位内容的时间点,该内容多是文本、图像、SVG 甚至 <canvas>
元素。
FMP:首次有效绘制。这是一个很主观的指标。根据业务的不一样,每个网站的有效内容都是不相同的,有效内容就是网页中"主角元素"。对于视频网站而言,主角元素就是视频。对于搜索引擎而言,主角元素就是搜索框。
TTI:可交互时间。用于标记应用已进行视觉渲染并能可靠响应用户输入的时间点。应用可能会由于多种缘由而没法响应用户输入:①页面组件运行所需的JavaScript还没有加载完成。②耗时较长的任务阻塞主线程
下面是参考文章中的一个例子,来直观表示上述的四种指标。
明确了上述的几个指标的含义后,下面介绍一下如何测量这几个指标的值。
现代浏览器已经为咱们提供了性能测试的api。直接上代码:
PerformanceObserver
在页面html代码顶部加入如下代码,订阅性能事件。
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
const metricName = entry.name;
const time = Math.round(entry.startTime + entry.duration);
console.log(entry);
console.log(metricName + ' : ' + time);
}
});
observer.observe({entryTypes: ['paint']});
复制代码
上述代码的输出以下:
下面的代码也是能够的:
window.performance.getEntriesByType('paint');
复制代码
FMP是一个十分主观的指标,须要开发者本身去测量。像文章一开始说的那样,咱们能够在业务逻辑中判断页面加载、渲染完成时记录一个时间戳,而后和window.performance.timing.fetchStart
相减,来获得FMP。
TTI也是一个较为主观的指标。浏览器并无为这个指标提供api。不过google提供了polyfill。下面是使用方法。
在页面html顶部加入:
!function(){if('PerformanceLongTaskTiming' in window){var g=window.__tti={e:[]};
g.o=new PerformanceObserver(function(l){g.e=g.e.concat(l.getEntries())});
g.o.observe({entryTypes:['longtask']})}}();
复制代码
install这个polyfill,
npm install tti-polyfill
复制代码
在业务代码中引用:
import ttiPolyfill from 'tti-polyfill';
...
ttiPolyfill.getFirstConsistentlyInteractive().then((tti) => {
console.log('tti', tti);
});
...
复制代码
getFirstConsistentlyInteractive()
方法接受可选的startTime
配置选项,让您能够指定下限值(您知道您的应用在此以前没法进行交互)。 默认状况下,该 polyfill 使用 DOMContentLoaded 做为开始时间,但一般状况下,使用主角元素呈现的时刻或您知道全部事件侦听器都已添加的时间点这类时间会更准确。
如何优化首屏速度?一提到这个topic,我首先想到的就是一系列写代码时应注意的原则,以及如下几个点:
一、充分利用缓存。
二、资源懒加载。
三、http请求层面的优化,好比上http2。
四、若是是客户端内的页面,能够作预加载等。
五、SSR。
....
本文不会深刻去讨论每一种方法具体应该怎么实施。在了解了文章中提到的几个关键性能指标后,能够针对页面加载的每个阶段,进行深刻的数据采集,分析和研究。在研究过程当中,天然能够知道页面到底慢在哪里,不一样的阶段使用不一样的方法进行优化。回到文章的标题,当考虑网页首屏速度优化时,咱们在考虑什么?其实就是在考虑经过一系列的方法,缩小网页的FP、FCP、FMP、TTI,以给用户提供良好的体验。
本文根据谷歌的参考文章,对页面加载过程当中的几个重要时间点进行了总结,明确、细化了首屏优化的方向和思路,符合预期。