1. 瀏覽器加載
- 傳統(tǒng)方法
<script>標簽打開defer
或async
屬性惕医,腳本就會異步加載抓于。渲染引擎遇到這一行命令,就會開始下載外部腳本羊异,但不會等它下載和執(zhí)行事秀,而是直接執(zhí)行后面的命令。
defer
與async
的區(qū)別是:defer
要等到整個頁面在內存中正常渲染結束(DOM 結構完全生成球化,以及其他腳本執(zhí)行完成)秽晚,才會執(zhí)行瓦糟;async
一旦下載完筒愚,渲染引擎就會中斷渲染,執(zhí)行這個腳本以后菩浙,再繼續(xù)渲染巢掺。一句話句伶,defer
是“渲染完再執(zhí)行”,async
是“下載完就執(zhí)行”陆淀。另外考余,如果有多個defer
腳本,會按照它們在頁面出現(xiàn)的順序加載轧苫,而多個async
腳本是不能保證加載順序的楚堤。 - 加載規(guī)則
瀏覽器加載 ES6 模塊,也使用<script>
標簽含懊,但是要加入type="module"
屬性身冬。
<script type="module" src="./foo.js"></script>
瀏覽器對于帶有type="module"
的<script>
,都是異步加載岔乔,不會造成堵塞瀏覽器酥筝,即等到整個頁面渲染完,再執(zhí)行模塊腳本雏门,等同于打開了<script>
標簽的defer
屬性嘿歌。如果網頁有多個<script type="module">
,它們會按照在頁面出現(xiàn)的順序依次執(zhí)行茁影。
一旦使用了async
屬性宙帝,<script type="module">
就不會按照在頁面出現(xiàn)的順序執(zhí)行,而是只要該模塊加載完成呼胚,就執(zhí)行該模塊茄唐。
對于外部的模塊腳本(上例是foo.js),有幾點需要注意蝇更。
代碼是在模塊作用域之中運行沪编,而不是在全局作用域運行。模塊內部的頂層變量年扩,外部不可見蚁廓。
模塊腳本自動采用嚴格模式,不管有沒有聲明use strict
厨幻。
模塊之中相嵌,可以使用import
命令加載其他模塊(.js
后綴不可省略,需要提供絕對 URL 或相對 URL)况脆,也可以使用export
命令輸出對外接口饭宾。
模塊之中,頂層的this
關鍵字返回undefined
格了,而不是指向window
看铆。也就是說,在模塊頂層使用this
關鍵字盛末,是無意義的弹惦。
同一個模塊如果加載多次否淤,將只執(zhí)行一次。
2. ES6 模塊與 CommonJS 模塊的差異
它們有兩個重大差異棠隐。
CommonJS 模塊輸出的是一個值的拷貝石抡,ES6 模塊輸出的是值的引用。
CommonJS 模塊是運行時加載助泽,ES6 模塊是編譯時輸出接口啰扛。
3. Node 加載
Node 對 ES6 模塊的處理比較麻煩,因為它有自己的 CommonJS 模塊格式嗡贺,與 ES6 模塊格式是不兼容的侠讯。目前的解決方案是,將兩者分開暑刃,ES6 模塊和 CommonJS 采用各自的加載方案厢漩。
Node 要求 ES6 模塊采用.mjs
后綴文件名。也就是說岩臣,只要腳本文件里面使用import
或者export
命令溜嗜,那么就必須采用.mjs
后綴名。require
命令不能加載.mjs
文件架谎,會報錯炸宵,只有import
命令才可以加載.mjs
文件。反過來谷扣,.mjs
文件里面也不能使用require
命令土全,必須使用import
。
目前会涎,這項功能還在試驗階段裹匙。安裝 Node v8.5.0 或以上版本,要用--experimental-modules
參數才能打開該功能末秃。
目前概页,Node 的import
命令只支持加載本地模塊(file
:協(xié)議),不支持加載遠程模塊练慕。
- 內部變量
ES6 模塊應該是通用的惰匙,同一個模塊不用修改,就可以用在瀏覽器環(huán)境和服務器環(huán)境铃将。為了達到這個目標项鬼,Node 規(guī)定 ES6 模塊之中不能使用 CommonJS 模塊的特有的一些內部變量。
首先劲阎,就是this關鍵字绘盟。ES6 模塊之中,頂層的this指向undefined
;CommonJS 模塊的頂層this指向當前模塊奥此,這是兩者的一個重大差異。
其次雁比,以下這些頂層變量在 ES6 模塊之中都是不存在的稚虎。
arguments
require
module
exports
__filename
__dirname
4. 循環(huán)加載
“循環(huán)加載”(circular dependency)指的是,a腳本的執(zhí)行依賴b腳本偎捎,而b腳本的執(zhí)行又依賴a腳本蠢终。