浏览器页面资源加载过程与优化

评价页面性能好坏的核心之一就是页面的加载速度,而页面加载速度的关键就是页面资源的加载。本文将从浏览器浏览器页面资源加载过程展开分析,来引出页面关键请求路径的概念,并给出如何优化该关键请求路径的一些方法。 下面相关内容,都是以chrome浏览器为例来进行介绍的。不一样浏览器之间,能够会略有差别,但基本过程是一致的。css

浏览器加载资源过程

首先抛出两个问题:html

  • 浏览器如何知道应该加载哪些资源?
  • 浏览器是什么顺序来加载这些资源? 当浏览器截获到一个页面请求后,将会按照顺序作以下图所示的4件事。
    流程
    流程
  1. 首先会将全部须要加载的资源进行分类。
  2. 而后根据浏览器相关的安全策略,来决定资源的加载权限。
  3. 接着对各个资源的加载优先级进行计算和排序。
  4. 最后一步,根据加载优先级顺序来加载资源。
第一步:资源分类

chrome浏览器会将资源分为14类,以下表所示。前端

类型 介绍
kMainResource 即主资源,html页面文件资源就属于该类型
kImage 各类图片资源
kCSSStyleSheet 顾名思义,就是层叠样式表css资源
kScript 脚本资源,例如js资源
kFont 字体资源,例如网页中经常使用的字体集.woff资源
kRaw 混合类型资源,最多见的ajax请求就属于这类资源
kSVGDocument SVG可缩放矢量图形文件资源
kXSLStyleSheet 扩展样式表语言XSLT,是一种转换语言,关于该类型能够查阅w3c XSL来了解
kLinkPrefetch HTML5页面的预读取资源(Link prefetch),例如dns-prefetch。下面会有详细介绍
kTextTrack video的字幕资源,- 即<track>标签
kImportResource HTML Imports,将一个HTML文件导入到其余HTML文档中,例如<link href="import/post.html" rel="import" />。详细了解请查阅相关文档。
kMedia 多媒体资源,video or audio都属于该类资源
kManifest HTML5 应用程序缓存资源
kMock 预留的测试类型
第二步:安全策略检查

网页安全政策(Content Security Policy,缩写 CSP)是由浏览器提供的一种白名单制度。开发者经过配置,来告诉浏览器各种外部资源的加载和执行限制,来提升网页的安全性。一种最经常使用的应用就是经过限制非信任域名脚本的加载来预防XSS攻击。 能够经过两种方式来配置CSP。 第一种,就是经过页面HTTP请求头的Content-Security-Policy字段来限制。以下图所示,这是www.google.com页面的请求头: web

流程
流程
第二种是,经过 <meta>标签来设置。 <meta>是以key-value的方式来进行配置的。下面以几个具体的应用例子来介绍。

  1. 用于预防XSS:
<meta http-equiv="Content-Security-Policy" content="script-src 'self'; style-src nos.netease.com kaola.com;">
复制代码

上面的script-src表明脚本资源;style-src表明样式资源;'self'表明只信任当前域名下的外来资源,其余域下的资源所有会被拦截;nos.netease.com kaola.com表明信任nos.netease.com和kaola.com这两个域名下的资源。 因此上面的标签的意义就是:对于脚本资源只信任本域下的,对于样式资源,除了本域还会加载nos.netease.com和kaola.com这两个域名下的。ajax

  1. 用于站点请求协议升级过渡(http转https):
<meta http-equiv="Content-Secur****ity-Policy" content="upgrade-insecure-requests">
复制代码

上面的upgrade-insecure-requests的意义,就如同字面意思同样:升级全部非安全请求。当加了这个meta标签之后,浏览器会将https页面中的全部htttp请自动升级到https。例如,当咱们须要进行全站http转https改造时,对于原有的大量http资源会直接强制以https或wss等SSL加密形式发送请求而不会报错。固然若是资源服务器不支持https等SSL加密,那么该资源仍是不会载入。chrome

  1. 用于阻止Mixed Content:
<meta http-equiv="Content-Security-Policy" content="block-all-mixed-content">
复制代码

混合内容(Mixed Content)就是第2个例子所说的,在https站点中,进行的http请求。这类在安全连接中混合了非安全请求内容就叫混合内容。出现这类请求时,咱们能够在浏览器控制台中找到对应的警告信息,以下图所示。 json

流程
流程
混合内容会下降HTTPS网站的安全性和用户体验。不过让人略感放心的是,浏览器对于可能对安全性形成较大威胁的资源类型的混合模式请求都会直接拦截报错,例如脚本资源,以下图所示。但对于图片、音频、视频等资源只会警告,但不会阻止其加载。
流程
流程
对于安全性要求极高的网站,能够经过上面的标签来阻止因此类型的非安全连接请求,这样包括图片、音频、视频等资源也将会被拦截报错。 固然对于Content-Security-Policy的设置还有不少其余做用,你们能够经过 MDN来作进一步了解。

第三步:资源优先级计算

资源的优先级被分为5级。不一样资料上,对这5级的命名描述上可能有所不一样。主要是由于资料自己多是从网络层面浏览器内核或者用户端控制台显示这三个方向中的某一个来讲的。这三个方向虽然对这5级的命名不一样,但都是一一对应的。 网络层面,5级分别为:Highest、Medium、Low、Lowest、Idle; 浏览器内核,5级分别为:VeryHigh、High、Medium、Low、VeryLow; 用户端控制台显示,5级分别为:Highest、High、Medium、Low、Lowest;后端

下面是以浏览器内核做为研究方向,来介绍浏览器的资源优先级计算过程:浏览器

  • 第一步,根据资源的类型来设定默认优先级。 对于每一类资源浏览器都有一个默认的加载优先级规则:
  1. html、css、font这三种类型的资源优先级最高;
  2. 而后是preload资源(经过<link rel=“preload">标签预加载)、script、xhr请求;
  3. 接着是图片、语音、视频;
  4. 最低的是prefetch预读取的资源。
  • 第二步,根据必定的实际规则,对优先级进行调整。 初始优先级设置好之后,浏览器会根据资源的实际属性和位于文档中的位置等方面,对优先级进行调整,来肯定出最终的加载优先级顺序。对于几个常见资源类型的调整规则以下:
  1. 对于XHR请求资源:将同步XHR请求的优先级调整为最高。 XHR请求能够分为同步请求和异步请求,浏览器会把同步请求的优先级提高到最高级,以便尽早获取数据、加快页面的显示。
  2. 对于图片资源:会根据图片是否在可见视图以内来改变优先级。 图片资源的默认优先级为Low。现代浏览器为了提升用户首屏的体验,在渲染时会计算图片资源是否在首屏可见视图以内,在的话,会将这部分视口可见图片(Image in viewport)资源的优先级提高为High。
  3. 对于脚本资源:浏览器会将根据脚本所处的位置和属性标签分为三类,分别设置优先级。 首先,对于添加了defer/async属性标签的脚本的优先级会所有降为Low。 而后,对于没有添加该属性的脚本,根据该脚本在文档中的位置是在浏览器展现的第一张图片以前仍是以后,又可分为两类。在以前的(标记early**)它会被定为High优先级,在以后的(标记late**)会被设置为Medium优先级。 下图总结了资源优先级计算后各种资源的优先级状况,其中特别将上面讲的三种常见资源的状况框了出来。红框框中的为脚本类型、紫框的为图片类型、蓝框为XHR请求。图片来源点此
    流程
    流程
第四步:按照上面计算的安全策略和优先级来加载或阻塞资源。

关键请求链和优化

上面详细介绍了浏览器的资源加载过程,其中核心在于资源的加载优先顺序的计算。咱们能够经过优化资源的加载优先级顺序,来有效提升页面的加载响应速度。缓存

首先来介绍下关键请求链(Critical-Request-Chains)的概念。可视区域渲染完毕(首屏),并对于用户来讲可用时,必须加载的资源请求队列,就叫作关键请求链。这样,咱们能够经过关键请求链,来肯定优先加载的资源以及加载顺序,以实现浏览器尽量快地加载页面。

如何查找页面的关键请求链
  1. 经过首屏快照获取关键image资源。 以下图所示,咱们经过首屏快照,来获取首屏所要加载的图片资源。(红框内)
    流程
    流程
  2. 经过LightHouse插件获取关键请求链中的关键js和css资源。 LightHouse详细的使用方法能够经过点击此处来了解。经过执行该插件最终能够生成一个报告,里面包含了有关该页面性能的全方面报告和建议。其中有关关键请求链的报告以下图所示:
    流程
    流程
  3. 经过浏览器控制台查看各个请求的优先级 打开Chrome控制台,切换到Network tab下,就能够查看资源的优先级(Priority)。若是没有Priority一栏,能够右键在下拉菜单中勾选Priority便可。以下图所示:
    流程
    流程
优化关键请求链

优化关键请求链有不少方法,这里主要介绍两种。

  • 第一种:利用PreloadPrefetch

    这两个标签在文章前面的介绍中就已经有所介绍,它们都属于预加载性能优化技术。对于开发人员,咱们可能比浏览器更加了解咱们的应用。从而可使用该技术来预先告知浏览器某些资源可能在未来会被使用到,让浏览器对这部分资源进行提早加载。 Preload:

    <link rel="preload" href="test.jpg">
    复制代码

    Prefetch: Prefetch包括资源预加载、DNS预解析、http预链接和页面预渲染。

    资源预加载:<link rel="prefetch" href="test.css">
    DNS预解析:<link rel="dns-prefetch" href="//haitao.nos.netease.com">
    http预链接:<link rel="prefetch" href="//www.kaola.com"> 将创建对该域名的TCP连接
    页面预渲染:<link rel="prerender" href="//m.kaola.com"> 将会预先加载连接文档的全部资源
    复制代码

    那么PrefetchPreload有什么区别呢? 具体来说,Preload来告诉浏览器预先请求当前页须要的资源,从而提升这些资源的请求优先级。好比,对于那些原本请求优先级较低的关键请求,咱们能够经过设置Prefetch来提高这些请求的优先级。 Prefetch来告诉浏览器用户未来可能在其余页面(非本页面)可能使用到的资源,那么浏览器会在空闲时,就去预先加载这些资源放在http缓存内,最多见的dns-prefetch。好比,当咱们在浏览A页面,若是会经过A页面中的连接跳转到B页面,而B页面中咱们有些资源但愿尽早提早加载,那么咱们就能够在A页面里添加这些资源Prefetch,那么当浏览器空闲时,就会去加载这些资源。 因此,对于那些可能在当前页面使用到的资源能够利用Prefetch,而对一些可能在未来的某些页面中被使用的资源能够利用Preload。若是从加载优先级上看,Prefetch会提高请求优先级;而Preload会把资源的优先级放在最低,当浏览器空闲时才去预加载。

    • 泼盆冷水: 既然PrefetchPreload做用如此强大,咱们是否能够放心使用呢?但实际上,除了dns-prefetch,其余的兼容性都十分堪忧。特别是在Safari上,因为苹果公司对安全性的苛刻要求,基本上对这些预加载技术都未实现支持。 Preload的支持性以下图所示,发现新版chrome支持较好,但Safari全军覆没。
      流程
      流程
      dns-prefetch支持性还不错。
      流程
      流程
      Prefetch一样的Safari全军覆没。
      流程
      流程
  • 第二种:利用LocalStorage。 既然第一种的预加载技术来进行资源缓存的支持性较差,那么一般能够利用LocalStorage来对部分请求的数据和结果进行缓存,省去发送http请求所消耗的时间,从而提升网页的响应速度。 这类作法在移动端应用已经十分普遍。下面分别介绍鹅、猫、狗三家页面是如何利用LS来进行请求缓存的。

  • 微信:利用LS来对js文件进行缓存。 以下图所示,用浏览器打开一篇微信公众帐号文章,打开控制台,发现Network里居然一个js文件都不须要加载?一脸懵逼!

    流程
    流程
    切到LS才哗然大悟,原来全部的JS都藏在这里了!
    流程
    流程
    微信就是利用了这种技巧来缓存关键路径里的js资源,从而大大加快了页面访问速度。 固然,实际实现起来,并不像表面看得那样,第一次访问时将js放到LS里,每次进来取出来执行这么简单,最核心的实际上是须要设计一套缓存更新机制。首先咱们对于缓存的js文件要经过后缀来设置独一无二的版本标识;其次,每次后端须要传一份资源配置文件,前端会根据这个配置文件来和LS中缓存的文件进行版本标识匹配,从而决定是利用LS缓存,仍是从新发请求更新资源。例如,微信中的这个配置文件就是经过moon_map来同步输出给前端的,以下图所示:
    流程
    流程

  • 天猫:利用LS来对关键的XHR异步请求进行缓存。 以天猫超市首页为例: 以下图,查看LS,发现其对首屏中的轮播和10个分类入口的数据进行了缓存。

    流程
    流程
    上面的json内容,格式化后,发现其中包含banner和flowIcons这两个属性,里面的数据分别对应的就是轮播和分类入口的数据。这样就能够大大提高首屏的渲染展现时间。

  • 京东:利用LS来对非关键请求进行缓存。 以PC版的京东首页为例。京东反向思惟,另辟奇径地采用了另外一种方式来利用LS。那就是把非关键请求剥离出来存放在LS内。 具体来讲,对于首屏数据,仍是正常加载和展现。但为了非首屏数据的加载和渲染会阻塞和抢占资源,从而影响首屏页面渲染。因此将非首屏资源的HTML/CSS等资源抽出来放在LS内,当页面滚动到可视区域时再去LS中获取数据,插入到dom中。这点很相似于如今的模块懒加载。以下图所示,每一个LS里都包含了一个模块所须要的HTML/CSS的资源。

    流程
    流程

PS:广告一波,网易考拉前端招人啦~有兴趣的戳我投递简历

END

参考资料:

  1. 从Chrome源码看浏览器如何加载资源:https://zhuanlan.zhihu.com/p/30558018。
  2. Preload,Prefetch 和它们在 Chrome 之中的优先级:https://yq.aliyun.com/articles/226240
  3. 聊聊浏览器资源加载优化:http://qingbob.com/let-us-talk-about-resource-load/
  4. 关键请求:http://www.zcfy.cc/article/the-critical-request-css-tricks-3843.html
  5. 其余:相关内容的MDN文档及Google Web Develop文档。
相关文章
相关标签/搜索