登录
前端开发页面时,都知道需要把 js 放到页面最下面,以期不影响页面展示、缩短白屏时间。
HTML 的 script 标签,是提供了两个属性,来配置 js 的阻塞影响、执行时机的。
使用了这两个属性,就更好的控制 script 引入的 js 对页面的加载时影响了。
html 在加载 js 时,是会阻塞后面的 html 加载和执行的。
比如如下代码,执行顺序如下:
当初始的 HTML 文档被完全加载和解析完成之后,DOMContentLoaded 事件被触发,而无需等待样式表、图像和子框架的完全加载。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script>
document.addEventListener('DOMContentLoaded', function(event) {
// 代码段 A
});
</script>
<script src="./index_1.js"></script>
<script src="./index_2.js"></script>
</head>
<body>
<div class="box_1"></div>
<script src="./index_3.js"></script>
<div class="box_2"></div>
</body>
<script src="./index_4.js"></script>
</html>
使用方法:
<script defer src="./index_3.js"></script>
defer 属性只对 src 引入的 js 生效
有 defer 属性的脚本,它的下载机制不变,还是会和其他脚本一起现在,但不会阻塞文档加载,也厚是它后面的元素和 js,不必等它下载完并执行完才能加载了。
如果上以案例中的 index_3.js 添加了 defer,即使 index_3.js 尚未加载完,它后面的元素和 js 也会正常展示和加载。
当有 defer 属性的脚本下载完成后,会先不执行,等到 Dom 是加载解析、DOMContentLoaded 事件之前,才会执行。
当然,如果有 defer 属性的脚本文件太大,DOMContentLoaded 也会暂不执行,直到这个 js 下载完、执行完后再执行。
综上所述,有 defer 属性的脚本,会和其他 js 文件一起下载,不会阻塞正常文档流,但会阻塞 DOMContentLoaded,他会等正常文档流加载完、即将执行 DOMContentLoaded时才执行,执行完成后,再执行 DOMContentLoaded。
所以,一些包含 dom 操作的 js,可以添加 defer 属性。
使用方法:
<script async src="./index_3.js"></script>
async 属性只对 src 引入的 js 生效
H5 新添的 script 标签的属性:async。
对于模块脚本,如果存在 async 属性,那么脚本及其所有依赖都会在延缓队列中执行,因此它们会被并行请求,并尽快解析和执行。
有 async 属性的脚本,会尽快开始下载,并尽快开始执行,即使其前面的 js 和 文档流还没有加载执行完也不影响,同时也不会阻塞其后面的 js 和 文档流,相当于完全脱离了文档流限制。
和下面的代码有一样的效果。
var script = document.createElement('script');
script.src = "./file.js";
document.querySelector('body').appendChild(script);