async, defer 以及 preload

Js脚本会改变DOM,在执行完脚本后HTML才会重新开始解析。CSS 可能会阻塞解析,取决于外部样式表和脚本在文档中的顺序。如果在文档中外部样式表放置在脚本之前,DOM 对象和 CSSOM 对象的构建可以互相干扰。 当解析器获取到一个 script 标签,DOM 将无法继续构建直到 JavaScript 执行完毕,而 JavaScript 在 CSS 下载完,解析完,并且 CSSOM 可以使用的时候,才能执行。即使 CSS 不阻塞 DOM 的构建,它也会阻塞 DOM 的渲染。直到 DOM 和 CSSOM 准备好之前,浏览器什么都不会显示(Flash of Unstyled Content 或是 FOUC)。

 

预加载

顺序下载与并行下载。

                          

 

主要的浏览器都会预加载:

  • 脚本

  • 外部 CSS

  • 来自 img 标签的图片

Firefox 也会预加载 video 元素的 poster 属性,而 Chrome 和 Safari 会预加载 @import 规则的内联样式。

在进行预解析时,浏览不会执行内联的 JavaScript 代码块。这意味着它不会发现任何的脚本注入资源,这些资源会排到抓取队列的最后面。

var script = document.createElement('script');
script.src = "//somehost.com/widget.js";
document.getElementsByTagName('head')[0].appendChild(script);

你可以把重要的资源放到 HTML 标签当中或者将要加载的脚本内联到文档的前面。不重要的资源晚一点被加载,可以通过 JavaScript 来加载他们来避免预解析。

 

defer 和 async

同步的脚本阻塞解析器仍旧是个问题。并不是所有的脚本对用户体验都是同等的重要,例如那些用于监测和分析的脚本。解决方法呢?就是去尽可能地异步加载这些不那么重要的脚本。

这两个属性都告诉浏览器,它可以 “在后台” 加载脚本的同时继续解析 HTML,并在脚本加载完之后再执行。这样,脚本下载就不会阻塞 DOM 构建和页面渲染了。结果就是,用户可以在所有的脚本加载完成之前就能看到页面。

 

defer 和 async 都只对外部脚本起作用,不同的是他们开始执行脚本的时机的不同。

defer 比 async 要先引入浏览器。它的执行在解析完全完成之后才开始,它处在DOMContentLoaded事件之前。 它保证脚本会按照它在 HTML 中出现的顺序执行,并且不会阻塞解析。

async 脚本在它们完成下载完成后的第一时间执行,它处在 window 的load 事件之前。 这意味着有可能(并且很有可能)设置了 async 的脚本不会按照它们在 HTML 中出现的顺序执行。这也意味着他们可能会中断 DOM 的构建。

               

设置async 的脚本的加载有着较低的优先级。他们通常在所有其他脚本加载之后才加载,而不阻塞 DOM 构建。然而,如果一个指定async 的脚本很快就完成了下载,那么它的执行会阻塞 DOM 构建以及所有在之后才完成下载的同步脚本。 

 

preload

同步的脚本总是比异步的脚本拥有更高的优先级。

对于那些重要的资源,你现在可以使用<link rel="preload"> 来告诉浏览器你需要尽快地加载它们。

<link rel="preload" href="very_important.js" as="script">
<link rel="preload" href="font.woff" as="font" crossorigin>

 

as 属性告诉浏览器要下载的是什么。可能的值有:

  • script

  • style

  • image

  • font

  • audio

  • video

preload 特性目前只有有限的支持度,因为其他浏览器还在推出它的过程中。你可以在这里查看进度。

 

转自:http://zcfy.cc/article/4224

 

posted @ 2017-10-09 11:57  wanghuohuo  阅读(389)  评论(0编辑  收藏  举报