两次导入JS模块会怎样?

让我们从一个问题开始。ES2015模块increment包含以下代码:

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

export default counter;

在另一个模块(我们将称为)中consumer,上述模块被导入了2次:

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

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

现在,实际上是一个问题。变量counter1counter2模块之后有consumer什么? 为了回答这个问题,您需要了解JavaScript如何执行模块以及如何导入模块。





模块执行


为了了解内部JavaScript机制是如何工作的,请仔细阅读规范

根据规范,每个JavaScript模块都与Module Record实体相关联此项具有Evaluate()模块执行的方法

如果此模块已经成功执行,则返回undefined;否则,返回false。[...]。否则,可传递地执行此模块的所有依赖项,然后执行此模块。
结果,证明同一模块仅执行一次。

不幸的是,您需要知道的回答我们的问题的不仅限于此。如何确保指令调用import 使用相同的路径会返回相同的模块吗?

允许导入命令


抽象操作HostResolveImportedModule()负责将模块(指定者)的路径与特定模块相关联模块导入代码如下所示:

import module from 'path';

规格说明

如下:HostResolveImportedModule的实现必须满足以下要求:

  • 正常的返回值应该是Module Record的特定子类的实例。
  • 如果对应于对referenceingScriptOrModule对的Module Record实体不存在,说明符不存在,或者无法创建这样的实体,则将引发异常。
  • 每次调用该操作并将其作为参数传递给特定的一对referenceingScriptOrModule指定符时,在其通常执行的情况下,它应返回Module Record实体的相同实例。

现在以更易理解的方式考虑这一点。

HostResolveImportedModule(referencingScriptOrModule, specifier)-一个抽象的操作,返回对应于一对的参数模块referencingScriptOrModulespecifier

  • 参数referencingScriptOrModule是当前模块,即导入的模块。
  • 参数specifier是与指令中的模块路径匹配的字符串import

在描述的最后,HostResolveImportedModule()可以说当导入对应于相同路径的模块时,将导入相同的模块:

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

// moduleA, moduleB  moduleC -    

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

有趣的是,该规范表明主机(浏览器,Node.js环境,通常是任何尝试执行JavaScript代码的主机)都应提供特定的实现HostResolveImportedModule()

回答


在仔细阅读了规范之后,很明显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'结果,结果是导入了模块的相同实例。

事实证明,相同的值1 写入到变量counter1counter2consumer

摘要


通过研究一个简单的问题,我们能够找到有关如何执行和导入JavaScript模块的更多信息。

导入模块时使用的规则非常简单:同一模块仅执行一次。换句话说,模块级别范围内的操作仅执行一次。如果再次导入已经执行过的模块,则不会再次执行。导入模块时,它使用从上一会话获得的结果来找出其确切导出的内容。

如果多次导入一个模块,但是模块说明符(指向它的路径)保持不变,那么JavaScript规范将确保导入相同的模块实例。

亲爱的读者们! 您多久阅读一次JavaScript规范,弄清某些语言结构的功能特性?


All Articles