网页控制script脚本异步执行方案,理解script标签defer属性
发布于 作者:苏南大叔 来源:程序如此灵动~对于一个网页来说,css
是放在顶部head
区域加载的,而js
是放在页脚body
的最下方加载的,这个是根据它们的特性所决定的。对于苏南大叔的页面来说,一个页面里面不会有很多个js
或者css
文件,它们都被使用grunt
合并成了一个文件。然后,css
放顶部,js
放底部,进行加载。所以理论上来说,并不会阻碍页面的加载,也不会影响页面加载线程。但是,普通的页面呢?
大家好,这里是苏南大叔的“程序如此灵动”博客,这里讲述苏南大叔和计算机代码的故事。本文讲述script
标签的defer
属性,本质上来说,defer
是用来异步加载的。那么,它的使用方式是怎么样的呢?
本文测试环境:win10
,chrome@100.0.4896.60
。
基本说明
defer
的意思是延迟(Deferred),并不是异步,虽然看起来效果确实是异步,但是其本意仅仅是延迟执行。给js
脚本添加 defer
属性,这个属性会让脚本的加载与文档的解析同步解析,然后在文档解析完成后再执行这个脚本文件,这样的话就能使页面的渲染不被阻塞。
在 HTML4.01 规范中规定:
设置后,这个布尔属性会向用户代理提示该脚本将不会生成任何网页内容(例如,JavaScript中不会生成 “document.write”),因此,用户代理可以继续解析和渲染。
测试代码
这里的测试代码,加上了type="module"
的es6 module
情况,有关说明文章见这里:
测试方式是通过浏览器访问web,并不是双击.html
文件。
这里测试以下几种代码:
<script type="module" src="./1.js"></script>
<script type="module" defer src="./2.js"></script>
<script type="module">
import aa from './3.js'
</script>
<script type="module" defer>
import aa from './4.js'
</script>
<script defer src="./5.js"></script>
<script src="./6.js"></script>
<script defer>
console.log("7.js");
</script>
<script>
console.log("8.js");
</script>
其中3.js
和4.js
都export
了一个空函数。
console.log("3.js");
export default ()=>{};
测试结果
这里先说基本原则:
defer
的意思是异步执行,被设置defer
的代码,在效果上会等待文档加载完毕后再执行,忽视其在页面中的物理位置。type="module"
的script
,直接默认就是defer
的。加不加defer
都是defer
。- 内联的
script
(就是把逻辑写在html
页面里面的,不是保存为一个文件的),默认都不是defer
的。加不加defer
都不是defer
。
然后苏南大叔在所有的被测试js
前面,再加个内联的onload
:
<script>
window.addEventListener('DOMContentLoaded', function () {
console.log('DOMContentLoaded')
})
</script>
然后,这8种js
,以及这个DOMContentLoaded
,到底谁先谁后呢?答案见下图:
结论是:先执行不defer
的,再执行defer
,最后执行DOMContentLoaded
。
特殊情况
在设置了defer
的.js
里面,使用document.write
语句的话。会得到警告信息,并且不会正确输出.write
信息。
Failed to execute 'write' on 'Document': It isn't possible to write into a document from an asynchronously-loaded external script unless it is explicitly opened.
参考文献
综述
本文讲述了script
的defer
属性,它可以把一些js
移动到后面执行,以免阻碍页面渲染。更多js
文章,可以点击:
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。