javascript - 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
(一个导入模块,即A
or C
)和一个字符串specifier
(类似于b.js
)。
有底线开始出现。
每次使用特定的
referencingScriptOrModule
,对作为参数调用此操作时,如果正常完成specifier
,它必须返回相同的实例。Module Record
我不能从这段摘录中得出一个保证A
,并且C
会得到相同的Module Record
代表实例,B
因为它们不是相同的对。(A, "b.js")
(C, "b.js")
这是否意味着,实际上,ES 模块系统不保证创建模块单例的可能性?从模块中导出单例实体有很多建议。据说一个模块被评估一次然后被缓存,所以这是处理单例的一种可接受的方式。然而,虽然关于缓存的说法是正确的,但这个事实本身并不意味着模块系统实现会解析为不同导入模块的相同导入模块。
解决方案
是的,ECMAScript 中没有任何保证——如何解析模块说明符的规则由主机决定。
多个不同
referencingScriptOrModule
的 ,specifier
对可能映射到同一个Module Record实例。实际的映射语义是实现定义的,但通常将规范化过程应用于说明符作为映射过程的一部分。典型的规范化过程将包括诸如字母大小写折叠以及相对和缩写路径说明符的扩展之类的操作。
因此,只有您的主机(如 node.js 或浏览器)才能保证它将始终将某些说明符解析为同一模块。
有很多示例(A, "b.js")
不(C, "b.js")
应该解析到同一个模块 - 例如,当A
是one/a.js时,它应该返回模块one/b.js,而C
可能是two/c.js并导致模块two/b .js。
推荐阅读
- android - Gradle Sync Failed: 错误: Expected ':' at line 1 column 11 path $.please
- jupyter-notebook - 在 Jupyter 笔记本/实验室中,如何在退出时自动重置变量?
- google-ads-api - 如何查找 Google Adwords 开发者令牌的权限级别
- reactjs - This.refs 用于功能组件(useRef、createRef)| 反应原生
- eclipse - 单击展开和折叠按钮 selenium cucumber eclipse
- python - ValueError:将字典输入传递给没有 FeatureLayer 作为第一层的顺序模型是错误的
- azure-devops - 无法使用 Azure DevOps API 检索自定义字段的标签
- powershell - 使用powershell从文件中提取数据并在新文件中排序
- node.js - 如果设置了 databasename,Mongoose 会超时
- angular - 我已经以角度实现了过滤器功能,但它不起作用