
普通 script 标签
- JS 可能会修改 HTML 和 CSS,所以 JS 的下载执行过程不能和 HTML / CSS 并行
- HTML 解析过程当中若碰到外联的 JS,会暂时停止 HTML 的解析流程,等候脚本下载和解析完成后再继续进行以前中断掉的 HTML 解析流程
- 这样就致使了 script 标签外联 JS 加载有这样的缺点:会影响整个页面效率,一旦网速很差整个网站将等待 JS 加载而不进行后续渲染,因为中断了 HTML 解析流程,因此致使页面空白,影响体验
- 之前的写法是将 script 标签写在 body 最后面,等 DOM 所有解析完成后才加载 JS,HTML5 标准有另外一套异步加载 JS 的方法
defer
- 在 script 标签的行间写一个
defer=“defer”
或直接写 defer
就可让这个 script 外联的 JS 变成异步加载了
- HTML 解析流程中若碰到外联 JS,会开辟新线程来下载脚本,下载完成后不会当即解析,不会阻塞 HTML 的解析流,等到 HTML 解析完毕后(不包括下载完里面的资源),再进行脚本的执行解析
- 该方法只有 IE 和一些高版本的 firefox 和 chrome 能够用
- 这种方式能够在 script 标签里面写代码
- 注意:IE6 和 IE7 的异步加载最多只能有 2 个,超过两个时必须等前两个加载完才会加载第三个
- 全部 defer 的 JS 代码都保证按照顺序执行
async
- async 是 asynchronous 的缩写,是 HTML5 标准,
- HTML 解析流程中若碰到外联 JS,会开辟新线程来下载脚本,下载完成后当即解析执行,且解析流程会中断 HTML 解析流程,等到脚本执行完成后才会继续进行以前中断掉的 HTML 解析流程
- 这种方法除了 IE6 ~ IE8 其余的浏览器都好用
- 该方式不能把代码写在 script 标签里,只能引用外部脚本(虽然标准是这么写的,但如今随着内核升级 async 的 script 标签里也能够写代码,在没有 src 状况下)
- async 的 JS 代码不能保证是顺序执行的,按照 race 的方式哪一个脚本先下载完就先解析哪一个脚本
- defer 和 async 这两个属性不能一块儿使用
兼容性写法
- 直接写两个 script 标签,一个是 defer 一个是 async,这种方法有缺陷,IE 高版本会加载两遍引发冲突,有些浏览器两个都没有,会一个都加载不出来
- 经过动态添加 script 标签,W3C 的标准规定动态添加的 script 标签是异步的
- 这里 src 部分的下载是异步的,不会阻塞后面的代码执行,便可一边把 script 插入到 DOM 中一边下载资源
<script>
function loadScript(url, callback) {
const script = document.createElement("script");
script.type = "text/javascript";
if (script.readyState) {
script.onreadystatechange = function() {
if (script.readeyState === "loaded" || script.readeyState === "complete") {
script.onreadystatechange = null;
callback && callback();
}
}
} else {
script.onload = function() {
callback && callback();
}
}
script.src = url;
document.body.appendChild(script);
}
</script>
复制代码