内容简介:浏览器从请求资源到资源下载下来,会经过多个阶段,一个请求生命周期的主要阶段包括:我们可以借助chrome的devtools查看,在network选项卡下,点击某个请求,选中Timing就可以看到devtools给我们提供的关于timing resource各个阶段的详细时间了。Queueing: 请求被阻塞,放入等待队列中等待。
浏览器从请求资源到资源下载下来,会经过多个阶段,一个请求生命周期的主要阶段包括:
- 重定向;如果服务器返回302的状态时,则会发生重定向,页面会重定向到302响应的location属性指定的地址去(response的Location属性指定,例如jd.com会被跳转到http://www.jd.com)。
- 读取浏览器缓存;如果资源的缓存时间还未过期(服务器设置的expires和cache-control还未过期),则会直接从浏览器缓存中读取。后续的dns查询、tcp握手、请求的发送都不会进行了。
- DNS解析;发送http请求需要通过建立TCP连接,建立TCP连接需要直到目标机器(服务器)的ip地址,所以需要进行dns的解析出ip,然后通过socket建立tcp连接。
- TCP握手;http建立在TCP上,需要先完成TCP三次握手,通过第2步的ip和已知的端口号,浏览器开启一个进程建立TCP连接。在此过程中,如果使用https,则会在TCP连接的时候进行SSL握手,建立SSL连接。
- 请求request;浏览器根据url,组装http请求,并发送。
- 接收response;服务器返回http响应的时候,浏览器接收到http response,然后就下载资源了。
查看各个阶段资源加载时间
devtools
我们可以借助chrome的devtools查看,在network选项卡下,点击某个请求,选中Timing就可以看到devtools给我们提供的关于timing resource各个阶段的详细时间了。
Queueing: 请求被阻塞,放入等待队列中等待。
一般以下几个原因会被阻塞:
1、如果这个资源加载优先级比较低,比如图片(html/css/js的优先级比图片高),那么图片请求就会被渲染引擎阻塞,等待优先级高的资源加载完成才从队列中取出,等待发送。
2、我们知道浏览器对同一域名下对TCP连接的并发数有限制(防止资源被消耗殆尽),chrome这边是6,那么如果同一域名下请求多于6的话,后面的请求就会被阻塞。
3、等待释放TCP连接
Stalled: 等待发送所用的时间,原因同上。
DNS Lookup:DNS查询时间
Initail connection:建立TCP连接所用的时间
SSL:建立SSL连接所用的时间
Request sent:发出请求的时间,通常不到一毫秒
TTFB:第一字节时间,即请求发出到接受到服务器第一个字节的时间,如果这个时间太长,一般有两个原因:
1、网络太差
2、服务器响应太慢
一般建议不要这个阶段的时间不要超过200毫秒。
Content Download:资源下载时间,如果被阻塞,则这个时间会很长,或者资源过大也会导致下载时间过长。例如js执行时间过长,那么图片加载下来的时间就会被拉到很长。
Resource Timing Api
现代浏览器提供了Api让用户可以查看图1各个阶段所消耗的时间,以便用户用Api获取资源加载过程中的具体情况,排查耗时的阶段,然后进行对应的优化。
通过window.performance.getEntriesByType('resource')获取所有的PerformanceResourceTiming:
if('performance' in window) { // 获取的是所有的PerformanceResourceTiming var resources = window.performance.getEntriesByType('resource') // 遍历各个资源加载的时间 resources.map((resource) => { // 这里以图片为例,判断图片加载的时间 if(resource.initiatorType === 'img') { // duration取的是整个过程中经历的时间,即图1的startTime到responseEnd直接的时间,即等于resource.responseEnd - resource.startTime if(resource.duration > 5000) { // 图片加载超过了5秒了,上报服务器,提示图片加载过长 reportToServer() } } }) } 复制代码
注意,上面的代码需要在onload事件上面执行(onload会在图片加载完毕以后调用)。
PerformanceResourceTimeing包含以下的属性:
- [x] initiatorType:资源的类型,有img、script、link
下面的属性是以毫秒为单位,对应图1
- [x] redirectStart
- [x] redirectEnd
- [x] fetchStart
- [x] domainLookupStart
- [x] domainLookupEnd
- [x] connectStart
- [x] connectEnd
- [x] secureConnectionStart
- [x] requestStart
- [x] responseStart
- [x] responseEnd
所以我们得出这样的一个计算:
查看DNS查询时间: domainLookupEnd - domainLookupStart
查看TCP三次握手时间: connectEnd - connectStart
request请求时间: responseEnd - responseStart
整个过程时间: responseEnd - startTime 或者 duration
资源加载
浏览器渲染过程(关键渲染路径)
1、根据HTML构建DOM树
2、根据css构建CSSOM规则树
3、根据DOM树和CSSOM树渲染合并渲染树
4、根据渲染树计算元素的位置和大小
5、将元素显示在屏幕上
在此过程中,解析到script会阻塞dom的解析和渲染(但其他资源的下载还是并行下载的)。执行完js后又会重新构建DOM树和CSSOM树,再构建渲染树,如此反复。
css加载
css被视为阻塞渲染的资源,不会阻塞dom的解析,但会阻塞dom的渲染。浏览器为了避免dom渲染完后,css样加载完再去渲染一次,就会阻塞dom的渲染。不然会有两次渲染,从性能上和用户体验上都不好。
如果把加载css放在body后,浏览器为了防止上面的状况的发生,会等待css加载完才去渲染dom,这样就会白屏了,所以建议css放在head里去加载。
所以,css放在head加载是一个很好的优化。
js加载
js即会阻塞dom的解析,也会阻塞dom的渲染。js是单线程的,在执行js的时候,浏览器会将控制权交给js,dom解析和渲染都会阻塞。
如果把js加载放在头部,那么dom的解析和渲染就停止了,这样会导致两个问题:
1、一方面,如果这时候js要获取dom或者操作dom都会报错。
2、另一方面,用户等待页面展示出来的时间也会加长,所以建议js加载放在底部。
备注:如果都放在head中,css在前,js在后,则浏览器为了让js获取到的样式是准确的,则会在css加载完前阻塞js的执行。如果把js写在前,css在后,浏览器会预加载css,这样的效果会比css在前阻塞后面的js执行好。
我们可以将script的加载设为异步加载,即defer/async,这样它就不会阻塞dom的解析和渲染。
结合以上,我们建议把css的引入放在head,把js的引入放在body之后,如果js可以异步加载,我们可以使用异步加载的方式。多说一句,现代浏览器有freload和frefetch的预加载,也可以提高页面加载速度,有兴趣的可以去查阅下资料。
以上所述就是小编给大家介绍的《利用Resource Timing监控资源加载速度》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 介绍同步加载、异步加载、延迟加载[原创]
- .net加载失败的程序集重新加载
- 虚拟机类加载机制:类加载时机
- 探秘类加载器和类加载机制
- hibernate中加载策略+批加载+懒加载异常【原创】
- [译] React 16.6 懒加载(与预加载)组件
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。