我们知道有 3 种方式在浏览器里加载 js 代码:
1:<script>…</script> 之间嵌入 js 代码**
2:<script src=’xx.js’></script> 通过 src 引入外部 js 文件**
3:加载 js 代码如 workers(例如 web worker 或者 service worker)
因为 js module 和纯粹的 js 脚本代码有不同之处(例如 js module 里的变量只在本 module 里面可见,不会加到 global,所以也不会挂在到 window 上),为了能加载 js module 代码,上面提到的 3 种机制都会有相应的改变。接下来就具体来看一下,浏览器加载 module 代码的机制:
1:js module 的加载依然有上面提到的三种方式
我们先来说前 2 种,也是我们最熟悉的通过 <script> 标签的方式:
<script src="./index.js" type="module"></script>
<script type="module">
console.log('in html')
</script>>
以 module 的方式加载,需要把 <script> 标签的 type 设置为‘module’,当没有设置 type 值的时候,默认是 ”text/javascript”。
2:defer 和 async
我们知道 <script> 标签还有 defer 和 async 这 2 个布尔型的属性,他们可以决定 js 代码的执行顺序,也会有 document 的解析产生影响,现在我们来看一下他们会对我们的模块加载产生怎样的影响:
defer
我们先来复习一下 defer 的特性:
1:带 defer 的 js 代码不会阻碍页面解析,js 代码的下载和页面的解析是同步进行的,js 代码的执行要等页面解析完成之后再开始。
2:加载多个带 defer 的 js 文件,会按照顺序执行。例如下面的一段代码,a.js 执行完之后才会下载 b.js 和执行 b.js.
<script src="./static/js/a.js" defer></script>
<script src="./static/js/b.js" defer></script>
3: defer 只对带 src 的从外部加载 js 文件的 <script> 有效,对于内嵌 js 代码的 <script>…</script> 是不起作用的。
<script type=’module’> 用 module 方式加载的 js,默认带有 defer 的属性,即具备 defer 的特效,上面提到的前 2 点都一样,只是第三点不同:即使内嵌 js 代码的 module,也具备 defer 的属性。例如:
<!-- 第一执行 index.js-->
<script src="./index.js" type="module"></script>
<!-- 第二执行内嵌 module-->
<script type="module">
console.log('in html')
</script>
<!-- 第三执行 main.js-->
<script src="./main.js" type="module"></script>
async
先来复习一下 async 的特性:
1:带有 async 的 <script> 的 js 文件下载不会阻塞页面解析,但是 js 文件一旦下载完,就会立即执行,假如这时候页面解析还没有完成,这就会阻塞页面解析。
2:多个带有 async 的 <script> 的 js 文件的执行顺序是无法确定的。
那如果 type=’module’ 又同时带有 async 的 <script> 文件的执行特性是怎样的呢?因为前面我们说了 type=’module’ 相当于默认带有 defer,但是我们知道 defer 和 async 是不同的。结论就是带有 async 的模块加载按照 async 的特性执行,例如:
<script src="./index.js" type="module" async></script>
<script src="./main.js" type="module" async></script>
到底是先执行 index.js 还是 main.js,这里是不能确定的。
3:加载 module 的时候文件路径
与加载常规的 js 代码不同的是,模块加载对文件路径有要求,下面 4 种是合法的:
1:以 / 开头的根目录
2:以 ./ 开头的当前路径
3:以 ../ 开头的父路径
4:一个 URL 路径
比如:
<!-- 以下为合法的文件路径 -->
<script src="/module1.js" type="module"></script>
<script src="./module2.js" type="module"></script>
<script src="../module/module3.js" type="module"></script>
<script src="https://www.xxxx.com/module/module4.js" type="module"></script>
<!-- 以下为不合法的文件路径 -->
<script src="module5.js" type="module"></script>
<script src="module/module5.js" type="module"></script>