深入理解浏览器加载资源的原理

1,293 阅读6分钟

浏览器加载资源的过程可以大致分为下面的4个步骤: 资源分类 ===> 资源安全策略检查 ===> 资源优先级计算 ===> 根据优先级下载资源

  • 浏览器对页面所有的资源进行了分类
  • 根据浏览器相关的安全策略, 来决定资源加载的权限
  • 接着对资源的加载的优先级进行计算和排序
  • 最后根据优先级顺序来下载资源

接下来按照这个顺序给大家解说。

资源分类

将常见的资源类型分为下面的10种:

  • 主资源: HTML
  • 样式资源: css
  • 字体资源: font(也就是Icon字体库)
  • 脚本资源: script
  • 图片: image
  • 混合类型资源: 常见的就是 xhr
  • 矢量图形资源: svg
  • media: 多媒体资源: vedio, audio, TextTrack(video的字幕)
  • manifest: 应用程序缓存资源
  • perfetch:预读取资源
type introduction
kMainResource html
kImage image
kCSSStyleSheet css
kScript js
kFont font
kRaw ajax
kSVGDocument SVG
kXSLStyleSheet XSLT
kLinkPrefetch Link prefetch, dns-prefetch
kTextTrack TextTrack
kImportResource HTML Imports
kMedia media
kManifest HTML5 application resource cache
kMock test type

安全策略检查(Content-Security-Policy,简称CSP)

也就是我们所说的网络白名单,限制浏览器对各类资源的加载,提高网站的安全性。一种常用的应用就是通过限制非信任域名的脚本加载来预防XSS攻击

白名单的设置可以分为两种:

  • 页面 HTTP Response 头的 Content-Security-Policy 字段来限制;
  • 通过 <meta> 标签来设置
  <meta http-equiv="Content-Security-Policy"  content="script-src 'self'; style-src nos.netease.com kaola.com;">

script-srcstyle-src 是资源的类型,常见的还有 img-srcself 表示当前网页的域名 nos.netease.com kaola.com 表示信任的域名 多个域名可以使用空格连接

SCP还可以用于站点请求协议升级过度(http转https)

  <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">

设置这个meta标签以后,浏览器会将https页面中的所有 http 请求自动升级到 https ;例如:当我们将全站中的 http 转成 https 时,对于原有的 http 强制转成 https 的形式发送,且不会报错。当然这个时候是需要服务器端支持的。

用于阻止Mixed Content

  <meta http-equiv="Content-Security-Policy" content="block-all-mixed-content">

混合内容 Mixed Content 就是指 https 页面中含有 http 的请求,这种在安全链接中混合了非安全请求内容就叫做混合内容(一般出现这种情况的时候可以在控制台中看到警告信息)

通过上面的标签来阻止所以类型的非安全链接请求,这样包括图片、音频、视频等资源也将会被拦截报错。

资源优先级计算

从浏览器内核考虑将资源分为5个等级(不同浏览器的等级名称可能不一样): VeryHigh ===> High ===> Medium ===> Low ===> VeryLow

根据资源的类型来设定默认优先级。 对于每一类资源浏览器都有一个默认的加载优先级规则:

  • VeryHigh: html、css、font这三类资源的优先级最高

  • High: HTML Imports(将一个HTML文件导入到其他HTML文档中,<link href="import/post.html" rel="import" />)、script、xhr请求

  • Medium: manifest 应用程序缓存资源

  • Low: 图片、音频、视频、SVG、TextTrack(video的字幕)

  • VeryLow: perfetch预读取的资源

根据一定的实际规则,对优先级进行调整

初始优先级设置好以后,浏览器会根据资源的实际属性和位于文档中的位置等方面,对优先级进行调整,来确定出最终的加载优先级顺序

  • 对于 XHR 请求资源:将同步 XHR 请求的优先级调整为最高。 XHR 请求可以分为同步请求和异步请求,浏览器会把同步请求的优先级提升到最高级,以便尽早获取数据、加快页面的显示

  • 对于图片资源:会根据图片是否在可见视图之内来改变优先级。 图片资源的默认优先级为Low。现代浏览器为了提高用户首屏的体验,在页面渲染时会计算图片资源是否在首屏可见视区以内,在的话,会将这部分可见图片(Image in viewport)资源的优先级提升为High。

  • 对于脚本资源:浏览器会将根据脚本所处的位置和属性标签分为三类:

    A:添加了 defer/async 属性标签的脚本的优先级会全部降为Low

    B:没有添加 defer/async 属性的脚本,且页面是否已经加载了一张非 preload 图片,来判断脚本在文档中的位置。如果页面已经加载了一张图片就认为这个script是页面偏底部的位置, 就把它的优先级调成medium

    C:否则就设置为high

如何对资源的加载进行优化

通过上面的安全策略和优先级的设置来加载和阻塞资源,我们可以通过优化资源的加载优先级顺序,来有效提高页面的加载响应速度。我们可以通过下面的技术来进行优化。

preloadprefetch

它们都属于预加载性能优化技术。预先告知浏览器某些资源可能在将来会被使用到,让浏览器对这部分资源进行提前加载

  <link rel="preload" href="xxxx.js">
  <link rel="preload" href="xxx.jpg">

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

  <link rel="prefetch" href="test.css">
  <link rel="dns-prefetch" href="//haitao.nos.netease.com">
  <link rel="prefetch" href="//www.kaola.com">
  <link rel="prefetch" href="//m.kaola.com">

最后两个分别是:http 预连接和页面预渲染。

preloadprefetch 的区别

preload 告诉浏览器预先请求当前页需要的资源,提高这些资源请求的优先级。对于那些本来请求优先级较低的关键请求,我们可以通过设置 preload 来提升这些请求的优先级。prefetch 告诉浏览器将来可能在其他页面(非本页面)或将来某个时候可能使用到的资源,那么浏览器会在空闲时,就去加载这些资源,最常见的 dns-prefetch。 看看浏览器对 preloadprefetch 的兼容性如何

prefetch

preload

dns-prefetch

localStorage

通常可以利用LocalStorage来对部分请求的数据和结果进行缓存,省去发送http请求所消耗的时间,从而提高网页的响应速度。 这类做法在移动端应用已经十分广泛。

最后

通过上面的分析,我们已经知道了浏览器对资源加载的过程,和如何进行优化。最后那么来捋一捋js和css资源放在文档不同位置时对其他资源的阻塞情况

image

上面的三种情况,很明显第一种和最后一种更优。那 <script> 放在头部位置和尾部有什么不一样。通过观察css的位置可以知道,第三种情况下留给用户的白屏的时间更短,因为在相同的情况下css越靠前那么就会越早完成解析,页面就也早呈现给用户。这就是为什么很多项目都将js资源放在文档底部的原因。

最后

希望疫情早点结束,为那些奋斗在一线的医护人员加油。(~在家都快憋疯了~)