本文摘自PHP中文网,作者青灯夜游,侵删。

前端当然要从 HTML 开始,我们来聊聊在 script 标签中加上 async/defer 时的功能及差异。
都明白的道理
我们都知道,浏览器解析 HTML 是一行一行按照顺序向后读取的,在传统的写法中,当浏览器读到 <script>
时,便会暂停解析 DOM,同时立即开始下载 <script>
中定义的资源,并在下载完成后立刻执行。由于这样的特性,可能会造成 DOM 树在还没有完全解析时就开始执行 JavaScript,需要操作 DOM 的程序可能因此无法正确执行,从而造成许多问题;或是由于 <script>
中的资源下载、执行时间过程,用户会卡在白画面,并会产生觉得网站太慢不好用之类的体验。
而解决方法也很简单,我们需要把 <script>
标签的位置都放到 <body>
的最后一行来避免 DOM 树解析不完全的问题,但是在复杂的网站中, HTML、JavaScript 的个头都很大,需要等到整个 DOM 树都载入完成才开始下载 <script>
内的资源,从网站读取完成到可操作,会产生明显的延迟感。
那这种问题该怎么解决呢?
从HTML4 开始,<script>
多了 defer
属性,而 HTML5 则多了 async
,两者都是用来帮助开发者控制 <script>
内资源的载入及执行顺序,以及避免 DOM 的解析被资源下载卡住的。
defer
defer
的意思是延迟(Deferred),在 HTML4.01 规范 中规定:
设置后,这个布尔属性会向用户代理提示该脚本将不会生成任何网页内容(例如,JavaScript中不会生成 “document.write”),因此,用户代理可以继续解析和渲染。
也就是说,在加上 defer
属性后,浏览器会继续解析、渲染画面,而不会因为需要载入<script>
内的资源而卡住;实际执行时,会在 DOMContentLoaded
执行之前,由上到下的依照摆放顺序触发。
听起来很方便对吧?但要提醒各位,虽然 W3C 规范上说 defer
属性会是一个布尔值,但 IE9 以前的版本是自定义的,即使写成 <script defer="false">
仍然会有 defer
的效果,使用时要特别注意。
又是你这个老不死的 IE……
async
async
的意思是异步(Asynchronous),在 HTML5 规范 中规定:
…如果存在 async 属性,则脚本将会在可用时立即异步执行 …
在 <script>
标签中加上 async
属性后,与defer
的相同点是也会在后台执行下载,但不同的是当下载完成会马上暂停 DOM 解析(如果还没有解析完成的话),并开始执行 JavaScript。因为下载完成后会立即执行,加上 async
属性后,就无法保证执行顺序了。
相关阅读 >>
更多相关阅读请进入《javascript》频道 >>

Vue.js 设计与实现 基于Vue.js 3 深入解析Vue.js 设计细节
本书对 Vue.js 3 技术细节的分析非常可靠,对于需要深入理解 Vue.js 3 的用户会有很大的帮助。——尤雨溪,Vue.js作者