3

在HTML里面使用javaScript有两种方式:

1: 通过<script>元素直接嵌入一段代码
2: 通过<script>元素的src属性引入外部js文件

当我们通过<script>元素引入外部js文件的时候,<script>元素本身的两个属性对整个页面的解析,js文件本身的下载和执行都会产生影响,这两个属性就是:defer, async
接下来的文章对js所有可能的情况一一总结
1: 通过<script>元素直接嵌入一段代码

<script>
    (function(){alert('hello')})()
</script>
<script>
    (function(){alert('javaScript')})()
</script>

以上的一段代码,如果是放在<head>里面,那么页面的解析(页面的解析是遇到<body>开始)就要等这两段script执行完了才会开始,并且规定那个先出现就先执行哪个,所以以上代码会先执行alert('hello'),再执行alert('javaScript')

如果上面的代码是放在body里面, 那上面代码的存在则会直接导致页面的解析,要等这段js代码执行完了,再继续页面解析的工作。

2:通过<script>元素的src属性引入外部js文件,但是没有defer和async

<script src="./static/js/a.js"></script>
<script src="./static/js/b.js"></script>

以上的情况浏览器会按照文件出现的先后顺序去下载和执行代码,意思就是b.js会在a.js执行完之后再执行。
如果上述代码是放在body里面,那么它也是阻塞的,如果用图表示的话就是:
image

3:通过<script>元素的src属性引入外部js文件,有async

<script src="./static/js/a.js" async></script>
<script src="./static/js/b.js" async></script>

遇到带有async属性的<script>标签,表示这个js文件的下载是异步的,意思就是它不会阻塞页面的解析,但是它一旦下载完,他的js代码就会被立即执行。如果用图表示的话就是:

image

从这个图对比上面的第2种情况,可以看出,在下载js文件的时候,页面的解析依然是在执行的,只是下载完之后js的执行会阻塞页面的解析。
如果遇到多个带async的<script>标签,那么他们的执行顺序是无法保证的。就像上面的代码,无法保证a.js一定会在b.js前面执行。

4: 通过<script>元素的src属性引入外部js文件,有defer

<script src="./static/js/a.js" defer></script>
<script src="./static/js/b.js" defer></script>

先来看一下defer的图像表示:

图片描述

defer只在<script>通过src去引入外部js文件时候才会起作用。

当<script>的type=module的时候,defer会被忽略,因为type=module的时候,<script>其实就是按照defer那样的特性工作的,所以在这种情况下加不加defer都不会改变type=module时的<script>下载好和解析的特性。

带有defer的<script>元素的下载同样不会阻塞页面的解析,并且它的执行也不会,因为它是等页面解析完成之后再执行的。如果遇到多个带defer的<script>元素,js代码的执行也会按照定义的顺序去执行。但是这两个脚本都会先于DOMContentLoaded事件执行。

**BUT, 在现实世界中,带defer的script不一定按照顺序执行,也不一定会先于DOMContentLoaded事件执行。


nanaistaken
583 声望43 粉丝