當一個模塊被導入兩次時,會發生什麼?

做者:Dmitri Pavlutin

翻譯:瘋狂的技術宅javascript

https://dmitripavlutin.com/ja...前端

未經容許嚴禁轉載java

讓咱們從一個問題開始。程序員

名爲 increment 的 ES2015 模塊包含如下代碼:面試

// increment.js
let counter = 0;
counter++;

export default counter;

而後在另外一個模塊 consumer 中,將上述模塊 increment 導入兩次:segmentfault

// consumer.js
import counter1 from './increment';
import counter2 from './increment';

counter1; // => ???
counter2; // => ???

問題是:當 consumer 模塊運行時,變量 counter1counter2 的內容是什麼?瀏覽器

要回答這個問題,首先你須要瞭解 JavaScript 如何評估和導入模塊。服務器

1. 模塊評估

理解 JavaScript 內部原理的一個好方法是查看其說明微信

根據規範,每一個 JavaScript 模塊都與模塊記錄相關聯。模塊記錄具備方法 Evaluate(),該方法對模塊進行評估:多線程


若是該模塊已經被成功評估,則返回 undefined;……不然,即可遞歸地評估此模塊全部的模塊依賴性,而後再評估此模塊。


因此同一模塊僅被評估一次。

不幸的是,問題不止於此。如何確保使用相同路徑兩次調用 import 語句返回相同的模塊?

2. 解決導入問題

將路徑(也稱爲說明符)關聯到具體模塊的職責由 HostResolveImportedModule() 執行操做。

import module from 'path';

根據規則:


HostResolveImportedModule 的實現必須符合如下要求:

  • 正常的返回值必須是 Module Record 的具體子類的實例。
  • 若是與 referencingScriptOrModule, specifier對相對應的 Module Record 不存在或沒法建立,則必須引起異常。
  • 每次使用特定的 referencingScriptOrModule, specifier 對做爲參數調用此操做時,若是正常完成,則必須返回相同的 Module Record 實例。

讓咱們以一種易於理解的方式看看都發生了什麼。

HostResolveImportedModule(referencingScriptOrModule, specifier) 是一個抽象操做,該操做返回對應於ReferencingScriptOrModule, specifier 的模塊:

  • 參數 referencingScriptOrModule 是當前模塊,即進行導入的模塊。
  • 參數 specifier 是對應 import 語句中模塊路徑的字符串。

最後,HostResolveImportedModule() 從相同路徑導入模塊時,將導入相同模塊:

import moduleA from 'path';
import moduleB from 'path';
import moduleC from 'path';

// moduleA, moduleB and moduleC are equal

moduleA === moduleB; // => true
moduleB === moduleC; // => true

有趣的是,規範指出主機(指瀏覽器,Node 或任未嘗試運行 JavaScript 的東西)必須提供 HostResolveImportedModule() 的具體實現。

3. 答案

查看規範以後,你將知道對 JavaScript 模塊進行了一次評估。另外,從相同路徑導入模塊時,將返回相同的模塊實例。

讓咱們回到問題。

increment 模塊老是被評估一次:

// increment.js
let counter = 0;
counter++;

export default counter;

無論 increment 模塊被導入多少次,counter++ 語句僅執行一次。默認導出的 counter 變量的值爲 1

如今看 consumer 模塊:

// consumer.js
import counter1 from './increment';
import counter2 from './increment';

counter1; // => 1
counter2; // => 1

import counter1 from './increment'import counter2 from './increment' 有相同的路徑:'./increment'。因此你將會導入相同的模塊實例。

最後,consumer 內部的 counter1counter2 變量都等於 1

4. 結論

僅經過研究提出的簡單問題,就能夠找到有關如何評估和導入 JavaScript 模塊的詳細信息。

規則很是簡單:同一模塊僅被評估一次,換句話說,模塊級做用於僅被執行一次。若是評估後的模塊再次導入,則會跳過第二次評估,並使用已解決的已導出文件。

若是某個模塊屢次導入但使用相同的說明符(即路徑),則 JavaScript 規範可確保你將獲得相同的模塊實例。


本文首發微信公衆號:前端先鋒

歡迎掃描二維碼關注公衆號,天天都給你推送新鮮的前端技術文章

歡迎掃描二維碼關注公衆號,天天都給你推送新鮮的前端技術文章

歡迎繼續閱讀本專欄其它高贊文章:


相關文章
相關標籤/搜索