背景大力教育的在線教室中臺(tái)提供封裝了核心能力的教室 SDK,業(yè)務(wù)方基于教室 SDK 開發(fā)面向用戶的在線教室 App 。最近對(duì)教室 SDK 做一次比較大的改動(dòng)時(shí),我遇到了一個(gè)懵逼的問題 。這個(gè)問題耗費(fèi)了我 3 天左右時(shí)間,讓我壓力一度大到全身發(fā)熱 。當(dāng)時(shí)雖然解決了問題,但并沒有很理解原因 。直到一個(gè)多月后,才有時(shí)間做一些更深入的分析,并寫下這篇文章 。
當(dāng)時(shí)的情況是,業(yè)務(wù)方 App 工程能通過 TypeScript 編譯,但在運(yùn)行時(shí)會(huì)報(bào)錯(cuò) 。就不同的使用教室 SDK 的方式,報(bào)錯(cuò)有兩種 。圖 1 為在業(yè)務(wù)方 App 工程里正常安裝教室 SDK 后進(jìn)行調(diào)試時(shí)的報(bào)錯(cuò);圖 2 為在業(yè)務(wù)方 App 工程里 yarn link 教室 SDK 后進(jìn)行調(diào)試時(shí)的報(bào)錯(cuò) 。

文章插圖

文章插圖
在分析這個(gè)問題前,需要先分析一下 JS(JavaScript)的模塊機(jī)制 。
CommonJS vs ES6 模塊CommonJS 與 ES6(ECMAScript 6)模塊有什么區(qū)別呢?《ECMAScript 6 入門教程 》[1]一書在“Module 的加載實(shí)現(xiàn)”章節(jié)指出兩個(gè)模塊體系有三個(gè)重大差異 。個(gè)人覺得這三個(gè)差異基本是錯(cuò)誤的,給大家造成了不少誤解 。后面再講質(zhì)疑的理由,這里先拋出我總結(jié)的幾點(diǎn)差異:
CommonJS 模塊由 JS 運(yùn)行時(shí)實(shí)現(xiàn),ES6 模塊借助 JS 引擎實(shí)現(xiàn);ES6 模塊是語(yǔ)言層面的底層的實(shí)現(xiàn),CommonJS 模塊是之前缺失底層模塊機(jī)制時(shí)在上層做的彌補(bǔ) 。從報(bào)錯(cuò)信息可以察覺這個(gè)差異 。CommonJS 模塊同步加載并執(zhí)行模塊文件,ES6 模塊提前加載并執(zhí)行模塊文件 。CommonJS 模塊在執(zhí)行階段分析模塊依賴,采用深度優(yōu)先遍歷(depth-first traversal),執(zhí)行順序是父 -> 子 -> 父;ES6 模塊在預(yù)處理階段分析模塊依賴,在執(zhí)行階段執(zhí)行模塊,兩個(gè)階段都采用深度優(yōu)先遍歷,執(zhí)行順序是子 -> 父 。CommonJS 模塊循環(huán)引用使用不當(dāng)一般不會(huì)導(dǎo)致 JS 錯(cuò)誤;ES6 模塊循環(huán)引用使用不當(dāng)一般會(huì)導(dǎo)致 JS 錯(cuò)誤 。CommonJS 模塊的導(dǎo)入導(dǎo)出語(yǔ)句的位置會(huì)影響模塊代碼執(zhí)行結(jié)果;ES6 模塊的導(dǎo)入導(dǎo)出語(yǔ)句位置不影響模塊代碼語(yǔ)句執(zhí)行結(jié)果 。為了方便說明,本文把 JS 代碼的運(yùn)行大致分為預(yù)處理和執(zhí)行兩個(gè)階段,注意,官方并沒有這種說法 。下面進(jìn)行更細(xì)致的分析 。
CommonJS 模塊在 Node.js 中,CommonJS 模塊[2]由 cjs/loader.js[3] 實(shí)現(xiàn)加載邏輯 。其中,模塊包裝器是一個(gè)比較巧妙的設(shè)計(jì) 。
在瀏覽器中,CommonJS 模塊一般由包管理器提供的運(yùn)行時(shí)實(shí)現(xiàn),整體邏輯和 Node.js 的模塊運(yùn)行時(shí)類似,也使用了模塊包裝器 。以下分析都以 Node.js 為例 。
模塊使用報(bào)錯(cuò)CommonJS 模塊使用不當(dāng)時(shí),由 cjs/loader.js 拋出錯(cuò)誤 。比如:
// Node.js internal/modules/cjs/loader.js:905 throw err; ^ Error: Cannot find module './none_existed.js' Require stack: - /Users/wuliang/Documents/code/demo_module/index.js可以看到,錯(cuò)誤是通過 throw 語(yǔ)句拋出的 。
模塊執(zhí)行順序CommonJS 模塊是順序執(zhí)行的,遇到 require 時(shí),加載并執(zhí)行對(duì)應(yīng)模塊的代碼,然后再回來執(zhí)行當(dāng)前模塊的代碼 。
如圖 3 所示,模塊 A 依賴模塊 B 和 C,模塊 A 被 2 個(gè) require 語(yǔ)句從上往下分為 3 段,記為 A1、A2、A3 。

文章插圖
如圖 4 所示,代碼塊執(zhí)行順序?yàn)椋篈1 -> B -> A2 -> C -> A3 。

文章插圖
模塊循環(huán)引用從 cjs/loader.js 的 L765、L772 和 L784 行代碼可以看到,在模塊執(zhí)行前就會(huì)創(chuàng)建好對(duì)應(yīng)的模塊對(duì)象,并進(jìn)行緩存 。模塊執(zhí)行的過程實(shí)際是在給該模塊對(duì)象計(jì)算需要導(dǎo)出的變量屬性 。因此,CommonJS 模塊在啟動(dòng)執(zhí)行時(shí),就已經(jīng)處于可以被獲取的狀態(tài),這個(gè)特點(diǎn)可以很好地解決模塊循環(huán)引用的問題 。
以上關(guān)于本文的內(nèi)容,僅作參考!溫馨提示:如遇健康、疾病相關(guān)的問題,請(qǐng)您及時(shí)就醫(yī)或請(qǐng)專業(yè)人士給予相關(guān)指導(dǎo)!
「愛刨根生活網(wǎng)」www.malaban59.cn小編還為您精選了以下內(nèi)容,希望對(duì)您有所幫助:- 怎么發(fā)面好 怎樣發(fā)面,如何發(fā)好面
- 現(xiàn)在網(wǎng)絡(luò)上流行什么詞
- 70年代的縫紉機(jī)現(xiàn)在值多少錢 70年代縫紉機(jī)回收價(jià)格
- “哭暈在廁所”這個(gè)網(wǎng)絡(luò)用語(yǔ)怎么來的?是什么意思
- 再開個(gè)店都綽綽有余 女子十年在美發(fā)店消費(fèi)150萬(wàn)
- 你支持現(xiàn)在的網(wǎng)絡(luò)用語(yǔ)嗎?各種縮寫,諧音相繼面世是好是壞?
- 劉德華鍛煉腹肌 每天有適量運(yùn)動(dòng)
- 女性在家徒手訓(xùn)練打造翹臀
- 蘋果在生活中的妙用
- 某年墨西哥等國(guó)出現(xiàn)了流感疫情,引發(fā)全球關(guān)注.在協(xié)助墨西哥等國(guó)家防控疫情傳播過程中發(fā)揮重要作用的國(guó)際
