首页 > 解决方案 > ES模块系统不保证模块单例吗?

问题描述

假设我们有一个依赖模块图,其中多个模块同时导入另一个模块,如下所示:(A) ---> (B) <--- (C)

似乎 ECMAScript 规范并不能保证两者A,并且C会获得代表B模块(或其导出实体)的对象的相同实例。

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

在代码评估之前,Module Record Link()会执行一个方法,然后它会递归地InitializeEnvironment()在每个 graph 上调用Module Record。的目的InitializeEnvironment()是为每个导入的模块创建绑定。为了获得Module Record代表其中之一的需要,此函数使用HostResolveImportedModule(). 它接收作为其参数referencingScriptOrModule(一个导入模块,即Aor C)和一个字符串specifier(类似于b.js)。

有底线开始出现。

每次使用特定的 referencingScriptOrModule,对作为参数调用此操作时,如果正常完成specifier,它必须返回相同的实例。Module Record

我不能从这段摘录中得出一个保证A,并且C会得到相同的Module Record代表实例,B因为它们不是相同的对。(A, "b.js")(C, "b.js")

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

标签: javascriptes6-modules

解决方案


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

多个不同referencingScriptOrModule的 ,specifier对可能映射到同一个Module Record实例。实际的映射语义是实现定义的,但通常将规范化过程应用于说明符作为映射过程的一部分。典型的规范化过程将包括诸如字母大小写折叠以及相对和缩写路径说明符的扩展之类的操作。

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

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


推荐阅读