聊聊ESM模块import会立即执行么?

前有科技后进阶 2025-01-22 04:32:42
1. 什么是模块记录

模块记录 (Module Record) 封装了有关单个 ES 模块的 import 和 export 的结构信息,此信息用于链接(Link)已连接模块的导入和导出。模块记录包含四个字段,这些字段仅在模块执行时使用。

出于规范目的,模块记录值是记录规范类型 (Record Specification Type) 的值,可以认为存在于简单的面向对象层次结构中,其中模块记录是一个具有具体子类的抽象类。ES 规范仅定义一个名为源文本模块记录 (Source Text Module Record) 的模块记录的具体子类。

下面的模块记录定义表列出了模块记录的所有字段,所有模块定义子类至少包含以下字段。

同时,模块记录还定义了很多抽象方法,所有模块定义子类都必须提供这些抽象方法的具体实现。

从上图中可以看到以下几个注意的点:

词法环境 Environment:包含此模块绑定的 顶级词法环境 (注意),字段在模块实例化时赋值是否执行 Evaluated:初始值为 false,如果此模块执行开始则为 true,执行完成仍为 trueGetExportedNames(exportStarSet):返回从该模块直接或间接导出的所有名称的列表ResolveExport(exportName, resolveSet, exportStarSet):返回此模块导出的名称的绑定,绑定表示为:{module: Module Record, bindingName: String}ModuleDeclarationInstantiation():递归地解析所有模块依赖关系并为模块创建 Module Environment RecordModuleEvaluation():如果模块代码已执行,则不执行任何操作。否则,先执行此模块的所有模块依赖项,然后再执行此模块代码,但必须在调用此方法之前完成 ModuleDeclarationInstantiation。 如果模块已经执行则不会再次执行。2. 从示例看 ES 模块重复执行问题

假如有一个模块示例,即 a.mjs:

// a.mjsconsole.log("......A 执行......");const a = "a";export default a;

下面是 b.mjs,其会导入 a.mjs 的模块:

// b.mjsimport a from "./a.mjs";import c from "./c.mjs"console.log('b 结束',a,c)

同时又有一个模块,即 c.mjs 也会导入 a.mjs 模块:

// c.mjsimport a from "./a.mjs";export default a;

此时,执行 b.mjs 的代码,输出结果如下:

......A 执行......b 结束 a a

从打印输出结果来看,至少印证了两点:

b.mjs 和 c.mjs 模块重复导入 a.mjs,但是代码只会执行一次被导入模块的顶级词法环境会在模块解析后确定,但是内部函数等的执行操作依然需要导入模块调用参考资料

https://262.ecma-international.org/6.0/#sec-abstract-module-record

https://www.linkedin.com/pulse/javascript-module-formats-asiri-hewage

https://stackoverflow.com/questions/67677807/can-i-import-a-module-without-execute-it-in-javascript

0 阅读:7
前有科技后进阶

前有科技后进阶

感谢大家的关注