ES模块系统不保证模块单例吗?

Doesn't ES module system guarantee module singleton?

假设我们有一个依赖模块图,其中多个模块同时导入另一个模块,类似这样:(A) ---> (B) <--- (C)

似乎 ECMAScript 规范不保证 AC 会获得表示 B 模块(或其导出实体)的相同对象实例。

即:一个 JS 模块由一个名为 Abstract Module Record (its concrete version is Source Text Module Record) 的规范对象实例表示。这种类型的对象,特别是存储模块的绑定(即,声明的变量名称及其相应的值)。换句话说,不同的 Module Record 有不同的绑定(这是一个非常简单的想法,因为这是我们倾向于使用模块的原因)。

在代码评估之前,Module Record Link() method is executed and it, in turn, recursively calls the InitializeEnvironment() on each of graph Module Records. The aim of InitializeEnvironment() is to create bindings for every imported module. To obtain the needed Module Record which would represent one of them, this function uses HostResolveImportedModule()。它接收参数 referencingScriptOrModule(一个导入模块,即 AC)和一个字符串 specifier(类似于 b.js)。

底线开始出现。

Each time this operation is called with a specific referencingScriptOrModule, specifier pair as arguments it must return the same Module Record instance if it completes normally.

我不能从这段摘录中得出保证 AC 会得到相同的实例 Module Record 代表 B 由于 (A, "b.js")(C, "b.js") 不是同一对。

这是否意味着,实际上,ES 模块系统不保证创建模块单例的可能性?有很多关于从模块中导出单例实体的建议。 模块被评估一次然后被缓存,所以这是处理单例的可接受方式。然而,虽然关于缓存的说法是正确的,但这个事实本身并不需要模块系统实现将解析为相同的导入模块 不同 导入模块。

是的,在 ECMAScript 中没有保证 - 如何解析模块说明符的规则由主机决定。

Multiple different referencingScriptOrModule, specifier pairs may map to the same Module Record instance. The actual mapping semantic is implementation-defined but typically a normalization process is applied to specifier as part of the mapping process. A typical normalization process would include actions such as alphabetic case folding and expansion of relative and abbreviated path specifiers.

因此只有您的主机(如 node.js 或浏览器)会向您保证它将始终将某些说明符解析为 相同 模块。

有许多示例 (A, "b.js")(C, "b.js") 不应 解析为同一模块 - 例如当 Aone/a.js 时,它应该 return 模块 one/b.js,而 C 可能是 two/c.js 并导致模块 two/b.js