Module加載的詳細說明-保證你有所收獲

模塊HTML 網頁中 , 瀏覽器通過<script>標簽加載 JavaScript 腳本 。<!-- 頁面內嵌的腳本 --><script type="application/javascript">// module code</script><!-- 外部腳本 --><script type="application/javascript" src="https://www.huyubaike.com/biancheng/path/to/myModule.js"></script>上面代碼中由于瀏覽器腳本的默認語言是 JavaScript 。因此type="application/javascript"可以省略 。瀏覽器同步加載 JavaScript 腳本可能會產生的問題默認情況下,瀏覽器是同步加載 JavaScript 腳本.即渲染引擎遇到<script>標簽就會停下來,等JavaScript腳本執行完后,再繼續向下渲染 。如果是外部腳本,還必須加入腳本下載的時間 。下載完成后,在執行 。如果腳本體積很大 , 下載和執行的時間就會很長,因此造成瀏覽器堵塞 。用戶會感覺到瀏覽器“卡死”了,沒有任何響應 。這顯然是很不好的體驗 。然后就出現了異步加載腳本的兩種語法異步加載腳本的兩種語法 defer或async<script src="https://www.huyubaike.com/biancheng/path/to/myModule.js" defer></script><script src="https://www.huyubaike.com/biancheng/path/to/myModule.js" async></script>上面代碼中,<script>標簽打開defer或async屬性 , 腳本就會異步加載 。渲染引擎遇到這一行命令,就會開始下載外部腳本,但不會等它下載和執行 , 而是直接執行后面的命令 。defer 與 async的區別是defer:要等到整個頁面在內存中正常渲染結束(DOM 結構完全生成,以及其他腳本執行完成),才會執行;async:一旦下載完 , 渲染引擎就會中斷渲染,執行這個腳本以后,再繼續渲染 。一句話 , defer是“渲染完再執行”,async是“下載完就執行” 。另外,如果有多個defer腳本 , 會按照它們在頁面出現的順序加載 , 而多個async腳本是不能保證加載順序的 。瀏覽器加載 ES6 模塊瀏覽器加載 ES6 模塊,也使用<script>標簽,但是要加入type="module"屬性 。<script type="module" src="https://www.huyubaike.com/biancheng/foo.js"></script>瀏覽器就知道這是一個es6模塊 。瀏覽器對于帶有type="module"的<script>,都是異步加載,不會造成堵塞瀏覽器 。即等到整個頁面渲染完,再執行<script type="module" src="https://www.huyubaike.com/biancheng/foo.js"></script>模塊腳本也就是說 type="module" 等價于 defer如果網頁有多個<script type="module">,它們會按照在頁面出現的順序依次執行 。模塊引入的注意點模塊之中,可以使用import命令加載其他模塊(.js后綴不可省略 , 需要提供絕對 URL 或相對 URL) 。也可以使用export命令輸出對外接口 。同一個模塊如果加載多次,將只執行一次 。ES6 模塊與 CommonJS 模塊的差異1.ommonJS 模塊輸出的是一個值的拷貝,輸出的是值 。ES6 模塊輸出的是值的引用 。2.CommonJS 模塊是運行時加載,ES6 模塊是編譯時輸出接口 。3.CommonJS 模塊的require()是同步加載模塊 。ES6 模塊的import命令是異步加載,詳細說下他們的第1個差異CommonJS 模塊輸出的是值的拷貝 , 也就是說 , 一旦輸出一個值 。模塊內部的變化就影響不到這個值 。請看下面這個模塊文件// lib.jsvar counter = 3;function incCounter() {counter++;}module.exports = {counter: counter,incCounter: incCounter,};上面代碼輸出內部變量counter和改寫這個變量的內部方法incCounter 。然后,在main.js里面加載這個模塊 。
// main.jsvar mod = require('./lib');console.log(mod.counter);// 3mod.incCounter(); //調用console.log(mod.counter); // 3上面代碼說明,lib.js模塊加載以后,它的內部變化就影響不到輸出的值 mod.counter 了 。這是因為mod.counter是一個原始類型的值 , 會被緩存 。除非寫成一個函數,才能得到內部變動后的值 。// lib.jsvar counter = 3;function incCounter() {counter++;}module.exports = {get counter() {return counter},incCounter: incCounter,};// main.jsvar mod = require('./lib');console.log(mod.counter);// 3mod.incCounter(); //調用console.log(mod.counter); // 4ES6 模塊的運行機制與 CommonJS 不一樣 。JS 引擎對腳本靜態分析的時候,遇到模塊加載命令import,就會生成一個只讀引用 。等到腳本真正執行時,再根據這個只讀引用到被加載的那個模塊里面去取值 。換句話說,ES6 的import有點像 Unix 系統的“符號連接”,原始值變了 , import加載的值也會跟著變 。因此,ES6 模塊是動態引用,并且不會緩存值,模塊里面的變量綁定其所在的模塊 。還是舉上面的例子 。

推薦閱讀