阅读 180

理解 async 与 defer

前置概念

在浏览器加载HTML过程中,HTML 解析器运行于主线程之中,并且在遇到 </script> 标签时会暂停 DOM 的解析与渲染,直到脚本中的内容被解析执行完成,才能继续解析渲染 DOM,这样也被称为“渲染阻塞”。
举个例子:
当我们写了这样一段代码后

image.png 当 HTML 解析器遇到 </script> 时,会去解析并执行</script>中的 index.js,这时 DOM 解析就会暂停,直观感受就是页面长时间的空白。
观察 chrome 性能面板可以直观看到这一现象。

image.png 通过时间线可以看到 script 脚本的执行会暂停 Parse HTML,在脚本执行完成之后继续执行了 这就是我们所说的渲染阻塞。

async

MDN说明:

对于普通脚本,如果存在 async 属性,那么普通脚本会被并行请求,并尽快解析和执行。该属性能够消除解析阻塞的 Javascript。

翻译一下:如果给 script 标签加上 async 属性,script 脚本中的内容会被异步加载,并且在加载完成之后会尽快(立即?)执行。
举个例子:
我们给</script>加上了 async 属性

image.png 再观察下 chrome 性能面板

image.png 可以看到,在脚本执行完成之后依然进行了 Parse HTML,这里会出现两种情况,如果 DOM 结构比较简单,内容比较少,在异步加载完脚完成本后 ,DOM 的解析已经完成,就不会再触发 Parse HTML,如果未完成会在异步脚本执行完成后继续解析。

defer

MDN说明:

这个布尔属性被设定用来通知浏览器该脚本将在文档完成解析后,触发 DOMContentLoaded (en-US) 事件前执行。有 defer 属性的脚本会阻止 DOMContentLoaded 事件,直到脚本被加载并且解析完成。

翻译一下:如果给 script 标签加上 defer 属性,script 脚本中的内容会被异步加载,并且在加载完成之后,如果 DOM 还未解析完成,会暂时挂起,等 DOM 解析完成后在执行。
举个例子:
我们给</script>加上了 defer 属性

image.png 观察下 chrome 性能面板

image.png 可以看到 </script>中的 index.js 的执行会在 DOM 解析完成后才开始执行。
结论:
async 属性虽然解析过程不会阻塞 DOM,但是解析完成后会很快执行,执行过程依然会阻塞 DOM defer 属性会等到 DOM 解析完成后执行脚本,不会阻塞 DOM 的解析过程

文章分类
前端
文章标签