ES6之Module 的加载实现(3)
4.循環(huán)加載
“循環(huán)加載”(circular dependency)指的是,a腳本的執(zhí)行依賴b腳本,而b腳本的執(zhí)行又依賴a腳本
通常,“循環(huán)加載”表示存在強耦合,如果處理不好,還可能導致遞歸加載,使得程序無法執(zhí)行,因此應該避免出現(xiàn)
但是實際上,這是很難避免的,尤其是依賴關系復雜的大項目,很容易出現(xiàn)a依賴b,b依賴c,c又依賴a這樣的情況。這意味著,模塊加載機制必須考慮“循環(huán)加載”的情況
對于JavaScript語言來說,目前最常見的兩種模塊格式CommonJS和ES6,處理“循環(huán)加載”的方法是不一樣的,返回的結(jié)果也不一樣
4.1CommonJS模塊的加載原理
CommonJS的一個模塊,就是一個腳本文件。require命令第一次加載該腳本,就會執(zhí)行整個腳本,然后在內(nèi)存生成一個對象
上面代碼就是Node內(nèi)部加載模塊后生成的一個對象。該對象的id屬性是模塊名,exports屬性是模塊輸出的各個接口,loaded屬性是一個布爾值,表示該模塊的腳本是否執(zhí)行完畢。其他還有很多屬性,這里都省略了
以后需要用到這個模塊的時候,就會到exports屬性上面取值。即使再次執(zhí)行require命令,也不會再次執(zhí)行該模塊,而是到緩存之中取值。也就是說,CommonJS模塊無論加載多少次,都只會在第一次加載時運行一次,以后再加載,就返回第一次運行的結(jié)果,除非手動清除系統(tǒng)緩存
4.2CommonJS模塊的循環(huán)加載
CommonJS模塊的重要特性是加載時執(zhí)行,即腳本代碼在require的時候,就會全部執(zhí)行。一旦出現(xiàn)某個模塊被”循環(huán)加載”,就只輸出已經(jīng)執(zhí)行的部分,還未執(zhí)行的部分不會輸出
上面代碼之中,a.js腳本先輸出一個done變量,然后加載另一個腳本文件b.js。注意,此時a.js代碼就停在這里,等待b.js執(zhí)行完畢,再往下執(zhí)行
再看b.js的代碼
上面代碼之中,b.js執(zhí)行到第二行,就會去加載a.js,這時,就發(fā)生了“循環(huán)加載”。系統(tǒng)會去a.js模塊對應對象的exports屬性取值,可是因為a.js還沒有執(zhí)行完,從exports屬性只能取回已經(jīng)執(zhí)行的部分,而不是最后的值
a.js已經(jīng)執(zhí)行的部分,只有一行
因此,對于b.js來說,它從a.js只輸入一個變量done,值為false
然后,b.js接著往下執(zhí)行,等到全部執(zhí)行完畢,再把執(zhí)行權交還給a.js。于是,a.js接著往下執(zhí)行,直到執(zhí)行完畢。我們寫一個腳本main.js,驗證這個過程
執(zhí)行main.js,運行結(jié)果如下
上面的代碼證明了兩件事。一是,在b.js之中,a.js沒有執(zhí)行完畢,只執(zhí)行了第一行。二是,main.js執(zhí)行到第二行時,不會再次執(zhí)行b.js,而是輸出緩存的b.js的執(zhí)行結(jié)果,即它的第四行
總之,CommonJS輸入的是被輸出值的拷貝,不是引用
4.3ES6模塊的循環(huán)加載
ES6處理“循環(huán)加載”與CommonJS有本質(zhì)的不同。ES6模塊是動態(tài)引用,如果使用import從一個模塊加載變量(即import foo from ‘foo’),那些變量不會被緩存,而是成為一個指向被加載模塊的引用,需要開發(fā)者自己保證,真正取值的時候能夠取到值
總結(jié)
以上是生活随笔為你收集整理的ES6之Module 的加载实现(3)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 只有程序员才懂这些黑色幽默!
- 下一篇: BXP网卡换槽之后就要按“任意键”的问题