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