本文原创:gaoruixiacss
提起前端性能优化,你们会想到哪些内容呢?html
相信不一样的人给出的答案不一样,关于性能优化没有标准答案,它更像是一个摸索的过程,本篇文章给出从页面加载的各个过程分析可优化的点前端
下面这张图是一个页面从打开到加载完成经历的各个阶段webpack
浏览器得到各个阶段的时间耗时的APIweb
- Timing标准:window.performance.timing
- Timing2标准: window.performance.getEntriesByType('navigation')[0]。
复制代码
Timing目前浏览器已再也不提供维护支持,Timing2获取的精度更加准确(比飞秒还精确,为10的-17次方秒),但兼容性尚且没有那么好(主要是iOS11才开始支持,其余浏览器都基本没问题了,IE9咱们就让它见鬼去吧)。在京麦插件性能统计中,咱们优先判断是否支持后者,除非后者不支持才使用前者。ajax
白屏时间json
从navigatorStart到responseEnd这段时间算做服务器时间
从浏览器开始加载页面到首次出现内容以前的这段时间(从页面发送一个页面URL请求出去,到服务器返回这个HTML的文本内容)后端
计算方式
- Timing: performance.timing.responseEnd - performance.timing.navigationStart
- Timing2: performance.getEntriesByType('navigation')[0].responseStart
复制代码
浏览器渲染时间浏览器
从responseEnd到loadEventEnd这段时间,包括CSS、JavaScript、Image等资源的加载耗时缓存
计算方式
- Timing: performance.timing.loadEventEnd - performance.timing.responseEnd
- Timing2: performance.getEntriesByType('navigation')[0].loadEventEnd - performance.getEntriesByType('navigation')[0].responseStart
复制代码
整页时间
从浏览器开始加载页面到整个页面加载完毕(最明显的标识就是移动端浏览器进度条读完了,pc端浏览器就是当前页签前面的loading消失了)
计算方式
- Timing: performance.timing.loadEventEnd - performance.timing.navigationStart
- Timing2: performance.getEntriesByType('navigation')[0].loadEventEnd
复制代码
能够打开浏览器控制台,切换到Performance,点击刷新按钮,等页面加载完成
先了解下获得html文本内容后页面的加载渲染流程(以webkit主流程为例)
渲染流程有四个主要步骤
以上步骤是一个渐进的过程,为了提升用户体验,渲染引擎试图尽量快的把结果显示给最终用户。它不会等到全部HTML都被解析完才建立并布局渲染树。它会在从网络层获取文档内容的同时把已经接收到的局部内容先展现出来。
阻塞渲染的因素
没有js的理想状况下,html与css会并行解析,分别生成DOM与CSSOM,而后合并成Render Tree,进入Rendering Pipeline; 但若是有js,css加载会阻塞后面js语句的执行,而(同步)js脚本执行会阻塞其后的DOM解析(因此一般会把css放在头部,js放在body尾)
CSS的阻塞状况
JS的阻塞状况
蓝色线表明网络读取,红色线表明执行时间,这俩都是针对脚本的;绿色线表明HTML解析
复制代码
由上能够得出影响整页时间的因素
下图中,在NetWork资源加载瀑布图中咱们能够查看是主要是哪些资源卡住了页面的整页时间,发送结束时间均可以观察到。以后再根据哪一个请求是瓶颈,对那个请求进行分析
使用插件pagespeed
首先去安装,安装完pagespeed以后,打开你要调试的网页,打开控制台的pagespeed,而后点击左上角的ANALYZE按钮,开始分析页面性能状况
插件Lighthouse相似,这里不详细介绍了
对于整页时间较长的状况,须要分析具体是在哪一个阶段致使整页时间比较长,能够从上面整页时间的说明里的各个阶段去分析
整页时间主要在dom解析耗时上,这段时间是从HTML开始解析,到JS所有执行完毕,这之中包含了CSS、JS等资源的加载,须要去优化HTML解析这段时间。
从经常使用性能优化指标咱们知道了页面加载总共分红下面这几个阶段:
重定向时间 -> DNS缓存查询时间 -> DNS查询时间 -> TCP链接时间 -> Request请求时间 -> Response请求响应时间 -> DOM解析时间 -> DOM渲染时间 -> Load事件执行时间
下面来看下各阶段的优化手段
这个很简单,就是请求到正确的地址上便可。
常常会出现的状况是:
https://xx.com/xx
,这样会致使浏览器重定向到https://xx.com/xx/
这个是浏览器作的处理,如Chrome浏览器对DNS的缓存时间是1分钟。
这个阶段咱们没法优化。
HTML的请求的DNS查询时间咱们没法缩短,但对于里面的其余域名的请求,咱们能够提早进行DNS查询,减小资源或者接口的请求时间。
在HTMl的头部head中加上DNS预查询便可
<link rel="dns-prefetch" href="//example.com">
通常对CDN须要用到的域名作解析便可。如下是CDN的各个域名:
TCP链接时间主要在3次握手中,缩短这个时间就是拉近用户和服务器机房的距离,对于接口的请求这个很难作到,但对于静态资源的TCP链接时间,咱们能够经过CDN全国节点缩短用户与服务器之间的距离。
另外,咱们还能够用HTTP2的keep-alive来保持长链接,这个CDN服务器默认是开启的,对于接口服务器也能够进行开启,虽然异步Ajax请求并不影响整页时间,但能让用户早点看到内容,何乐而不为。
在Request请求中,请求返回的时间取决于服务器的处理时间。
对于先后端耦合的项目或者SSR的项目,由于须要处理逻辑,拿出数据再动态构建HTML文本,以后再将HTML文本返回给浏览器,那这段时间主要在于处理逻辑上。
对于先后端分离的项目,由于返回的是一个空的HTML文本,数据都是等JS调用Ajax获取的,因此HTML的Request请求时间很短。但这样咱们得处理Ajax请求,它也有Request请求的时间,这个也得看怎么在服务端进行性能提高。
虽然Ajax请求不计算在整页时间中,但也别为了缩短整页时间而选择先后端分离,这个并非它的优点所在。用户关心的是页面何时加载完,这其中包含数据何时展示,因此别为了整页时间的优化而优化,而应该关心用户体验,就算是Ajax接口也应该考虑怎么提高性能。
并且使用先后端分离其实会加长页面的白屏时间,这个也是一个衡量页面性能的一个重要指标,白屏时间能够经过添加骨架屏来优化。
对于静态资源的请求,通常资源越小,请求越快(也受服务器带宽的影响)。能够经过减少静态资源(JS、CSS、图片等)请求的大小从而来缩短请求响应时间。
这段时间从服务器响应返回HTML文本,浏览器开始按照从上到下的执行顺序解析HTML文本,到执行完HTML中的全部JS,这段时间咱们将其称为DOM解析时间。因此优化这段时间在于缩短HTML中的CSS文件和JS文件的请求时间和执行时间,以及缩短HTML的解析时间。
能够从如下几方面来作
这个时间就在于减小重排(页面布局变更)和重绘(页面从新渲染元素样式)
减小重排和重绘的手段
这个时间的压缩就是减小onload回调函数的耗时处理
不少人习惯将事件绑定放在onload事件中,实际上是能够将其提早,放在尾部JS中直接执行或者DOMContentLoaded事件中,这时候DOM解析完成了,已经能够获取到DOM节点了
本文从页面加载的各个阶段分析影响因素,简单的给出了可优化的方向,具体实施还须要在工做中结合团队现状来进行