页面模式偏好

16 ECMAScript 语言:脚本和模块

16.1 脚本

语法

Script : ScriptBodyopt ScriptBody : StatementList[~Yield, ~Await, ~Return]

16.1.1 Static Semantics: 提前错误

Script : ScriptBody ScriptBody : StatementList

16.1.2 Static Semantics: ScriptIsStrict

语法制导操作 ScriptIsStrict,接收无参数;返回值:Boolean。 它按以下产生式分别定义:

Script : ScriptBodyopt
  1. 如果存在 ScriptBody,并且 ScriptBody 的指令序言包含 Use Strict 指令,则返回 true。
  2. 返回 false。

16.1.3 Runtime Semantics: Evaluation

Script : [empty]
  1. 返回 undefined。

16.1.4 Script Records

Script Record 封装有关正在求值的脚本的信息。每个 script record 都包含 表 35 中列出的字段。

表 35: Script Record 字段
字段名称 值类型 含义
[[Realm]] a Realm Record 创建此脚本的 realm。
[[ECMAScriptCode]] a Script Parse Node 解析此脚本源文本的结果。
[[LoadedModules]] a List of LoadedModuleRequest Records 从此脚本导入的说明符字符串到已解析 Module Record 的映射。此列表不包含两个不同的 Record r1 和 r2,使得 ModuleRequestsEqual(r1, r2) 是 true。
[[HostDefined]] anything (default value is empty) 保留给需要将附加信息与脚本关联的宿主环境使用的字段。

16.1.5 ParseScript ( sourceText, realm, hostDefined )

抽象操作 ParseScript,接收参数 sourceText ((String 或 a sequence of Unicode code points))、realm (Realm 记录) 和 hostDefined (任意值);返回值:(Script 记录 或 a non-empty List of SyntaxError objects)。 它根据将 sourceText 作为 Script 解析的结果创建 Script Record。 调用时执行以下步骤:

  1. 令 script 为 ParseText(sourceText, Script)。
  2. 如果 script 是错误的 List,则返回 script。
  3. 返回 Script Record { [[Realm]]: realm, [[ECMAScriptCode]]: script, [[LoadedModules]]: « », [[HostDefined]]: hostDefined }。
注

实现可以在对该脚本源文本执行 ParseScript 之前解析脚本源文本,并分析其中的提前错误条件。不过,任何错误的报告都必须推迟到本规范实际对该源文本执行 ParseScript 时。

16.1.6 ScriptEvaluation ( scriptRecord )

抽象操作 ScriptEvaluation,接收参数 scriptRecord (Script 记录);返回值:(正常完成 (值:ECMAScript 语言值) 或 突兀完成)。 调用时执行以下步骤:

  1. 令 globalEnv 为 scriptRecord.[[Realm]].[[GlobalEnv]]。
  2. 令 scriptContext 为新的 ECMAScript 代码执行上下文。
  3. 将 scriptContext 的 Function 设置为 null。
  4. 将 scriptContext 的 Realm 设置为 scriptRecord.[[Realm]]。
  5. 将 scriptContext 的 ScriptOrModule 设置为 scriptRecord。
  6. 将 scriptContext 的 VariableEnvironment 设置为 globalEnv。
  7. 将 scriptContext 的 LexicalEnvironment 设置为 globalEnv。
  8. 将 scriptContext 的 PrivateEnvironment 设置为 null。
  9. 挂起正在运行的执行上下文。
  10. 将 scriptContext 压入执行上下文栈;scriptContext 现在成为正在运行的执行上下文。
  11. 令 scriptNode 为 scriptRecord.[[ECMAScriptCode]]。
  12. 令 result 为 Completion(GlobalDeclarationInstantiation(scriptNode, globalEnv))。
  13. 如果 result 是正常完成,则
    1. 将 result 设置为 Completion(scriptNode 的 Evaluation)。
    2. 如果 result 是正常完成,并且 result.[[Value]] 是 empty,则
      1. 将 result 设置为 NormalCompletion(undefined)。
  14. 挂起 scriptContext 并将其从执行上下文栈中移除。
  15. 断言:执行上下文栈不为空。
  16. 恢复当前位于执行上下文栈顶部的上下文,并将其作为正在运行的执行上下文。
  17. 返回 ? result。

16.1.7 GlobalDeclarationInstantiation ( script, envRecord )

抽象操作 GlobalDeclarationInstantiation,接收参数 script (a Script Parse Node) 和 envRecord (Global Environment 记录);返回值:(正常完成 (值:unused) 或 抛出完成)。 script 是正在为其建立执行上下文的 Script。envRecord 是将在其中创建绑定的全局环境。

注 1

当为脚本求值建立执行上下文时,会在当前全局环境中实例化声明。代码中声明的每个全局绑定都会被实例化。

调用时,它执行以下步骤:

  1. 令 lexicalNames 为 script 的 LexicallyDeclaredNames。
  2. 令 variableNames 为 script 的 VarDeclaredNames。
  3. 对 lexicalNames 的每个元素 name,执行
    1. 如果 HasLexicalDeclaration(envRecord, name) 是 true,则抛出 SyntaxError 异常。
    2. 令 hasRestrictedGlobal 为 ? HasRestrictedGlobalProperty(envRecord, name)。
    3. 注:全局 var 和 function 绑定(由非严格直接 eval 引入的绑定除外)不可配置,因此属于受限全局属性。
    4. 如果 hasRestrictedGlobal 是 true,则抛出 SyntaxError 异常。
  4. 对 variableNames 的每个元素 name,执行
    1. 如果 HasLexicalDeclaration(envRecord, name) 是 true,则抛出 SyntaxError 异常。
  5. 令 variableDecls 为 script 的 VarScopedDeclarations。
  6. 令 funcsToInitialize 为新的空 List。
  7. 令 declaredFuncNames 为新的空 List。
  8. 按 List 的逆序,对 variableDecls 的每个元素 variableDecl,执行
    1. 如果 variableDecl 不是 VariableDeclaration、ForBinding 或 BindingIdentifier 中的任何一个,则
      1. 断言:variableDecl 是 FunctionDeclaration、GeneratorDeclaration、AsyncFunctionDeclaration 或 AsyncGeneratorDeclaration 之一。
      2. 注:如果同一个名称有多个函数声明,则使用最后一个声明。
      3. 令 funcName 为 variableDecl 的 BoundNames 的唯一元素。
      4. 如果 declaredFuncNames 不包含 funcName,则
        1. 令 funcDefinable 为 ? CanDeclareGlobalFunction(envRecord, funcName)。
        2. 如果 funcDefinable 是 false,则抛出 TypeError 异常。
        3. 将 funcName 追加到 declaredFuncNames。
        4. 将 variableDecl 插入为 funcsToInitialize 的第一个元素。
  9. 令 declaredVariableNames 为新的空 List。
  10. 对 variableDecls 的每个元素 variableDecl,执行
    1. 如果 variableDecl 是 VariableDeclaration、ForBinding 或 BindingIdentifier 之一,则
      1. 对 variableDecl 的 BoundNames 的每个 String name,执行
        1. 如果 declaredFuncNames 不包含 name,则
          1. 令 variableDefinable 为 ? CanDeclareGlobalVar(envRecord, name)。
          2. 如果 variableDefinable 是 false,则抛出 TypeError 异常。
          3. 如果 declaredVariableNames 不包含 name,则
            1. 将 name 追加到 declaredVariableNames。
  11. 注:如果全局对象是普通对象,则在此算法步骤之后不会发生异常终止。不过,如果全局对象是 Proxy 异质对象,则它可能表现出会导致以下某些步骤异常终止的行为。
  12. Normative Optional
    如果宿主是 Web 浏览器或以其他方式支持 块级函数声明的 Web 遗留兼容性语义,则
    1. 令 strict 为 script 的 ScriptIsStrict。
    2. 如果 strict 是 false,则
      1. 令 declaredFuncOrVariableNames 为 declaredFuncNames 和 declaredVariableNames 的列表连接。
      2. 对直接包含在任意 Block、CaseClause 或 DefaultClause x 的 StatementList 中、且 script Contains x 是 true 的每个 FunctionDeclaration funcDecl,执行
        1. 令 funcName 为 funcDecl 的 BindingIdentifier 的 StringValue。
        2. 如果将 FunctionDeclaration funcDecl 替换为以 funcName 作为 BindingIdentifier 的 VariableStatement 不会为 script 产生任何提前错误,则
          1. 如果 HasLexicalDeclaration(envRecord, funcName) 是 false,则
            1. 令 funcDefinable 为 ? CanDeclareGlobalVar(envRecord, funcName)。
            2. 如果 funcDefinable 是 true,则
              1. 注:只有当 funcName 既不是 VarDeclaredName,也不是另一个 FunctionDeclaration 的名称时,才会在这里实例化 funcName 的 var 绑定。
              2. 如果 declaredFuncOrVariableNames 不包含 funcName,则
                1. 执行 ? CreateGlobalVarBinding(envRecord, funcName, false)。
                2. 将 funcName 追加到 declaredFuncOrVariableNames。
              3. 当对 FunctionDeclaration funcDecl 求值时,执行以下步骤,以替代 15.2.6 中提供的 FunctionDeclaration Evaluation 算法:
                1. 令 globalEnv 为正在运行的执行上下文的 VariableEnvironment。
                2. 令 blockEnv 为正在运行的执行上下文的 LexicalEnvironment。
                3. 令 funcObj 为 ! blockEnv.GetBindingValue(funcName, false)。
                4. 执行 ? globalEnv.SetMutableBinding(funcName, funcObj, false)。
                5. 返回 unused。
  13. 令 lexicalDecls 为 script 的 LexicallyScopedDeclarations。
  14. 令 privateEnv 为 null。
  15. 对 lexicalDecls 的每个元素 lexicalDecl,执行
    1. 注:词法声明的名称仅在此处实例化,而不会初始化。
    2. 对 lexicalDecl 的 BoundNames 的每个元素 name,执行
      1. 如果 lexicalDecl 的 IsConstantDeclaration 是 true,则
        1. 执行 ? envRecord.CreateImmutableBinding(name, true)。
      2. 否则,
        1. 执行 ? envRecord.CreateMutableBinding(name, false)。
  16. 对 funcsToInitialize 的每个 Parse Node funcDecl,执行
    1. 令 funcName 为 funcDecl 的 BoundNames 的唯一元素。
    2. 令 funcObj 为以 envRecord 和 privateEnv 为参数对 funcDecl 执行 InstantiateFunctionObject 的结果。
    3. 执行 ? CreateGlobalFunctionBinding(envRecord, funcName, funcObj, false)。
  17. 对 declaredVariableNames 的每个 String variableName,执行
    1. 执行 ? CreateGlobalVarBinding(envRecord, variableName, false)。
  18. 返回 unused。
注 2

16.1.1 中规定的提前错误会阻止单个 Script 内函数/var 声明与 let/const/class 声明之间的名称冲突,以及 let/const/class 绑定的重复声明。不过,跨越多个 Script 的此类冲突和重复声明会在 GlobalDeclarationInstantiation 期间作为运行时错误检测。如果检测到任何此类错误,则不会为该脚本实例化任何绑定。不过,如果使用 Proxy 异质对象定义全局对象,则针对冲突声明的运行时测试可能不可靠,从而产生突然完成,并导致某些全局声明未被实例化。如果发生这种情况,则不会对 Script 的代码求值。

与显式 var 或函数声明不同,直接在全局对象上创建的属性会产生可被 let/const/class 声明遮蔽的全局绑定。

16.2 模块

语法

Module : ModuleBodyopt ModuleBody : ModuleItemList ModuleItemList : ModuleItem ModuleItemList ModuleItem ModuleItem : ImportDeclaration ExportDeclaration StatementListItem[~Yield, +Await, ~Return] ModuleExportName : IdentifierName StringLiteral

16.2.1 模块语义

16.2.1.1 Static Semantics: 提前错误

ModuleBody : ModuleItemList 注

重复 ExportedNames 规则意味着,一个 ModuleBody 中包含多个 export default ExportDeclaration 项是语法错误。与冲突或重复声明相关的其他错误条件会在对 Module 求值之前的模块链接期间检查。如果检测到任何此类错误,则不会对该 Module 求值。

ModuleExportName : StringLiteral

16.2.1.2 Static Semantics: ImportedLocalNames ( importEntries )

抽象操作 ImportedLocalNames,接收参数 importEntries (列表 (元素:ImportEntry 记录));返回值:列表 (元素:String)。 它创建由 importEntries 定义的所有局部名称绑定的 List。 调用时执行以下步骤:

  1. 令 localNames 为新的空 List。
  2. 对 importEntries 的每个 ImportEntry Record importEntry,执行
    1. 将 importEntry.[[LocalName]] 追加到 localNames。
  3. 返回 localNames。

16.2.1.3 ModuleRequest Records

ModuleRequest Record 表示使用给定导入属性导入模块的请求。它由以下字段组成:

表 36: ModuleRequest Record 字段
字段名称 值类型 含义
[[Specifier]] a String 模块说明符
[[Attributes]] a List of ImportAttribute Records 导入属性

LoadedModuleRequest Record 表示导入模块的请求以及由此得到的 Module Record。它由表 表 36 中定义的相同字段组成,并额外包含 [[Module]]:

表 37: LoadedModuleRequest Record 字段
字段名称 值类型 含义
[[Specifier]] a String 模块说明符
[[Attributes]] a List of ImportAttribute Records 导入属性
[[Module]] a Module Record 与此模块请求对应的已加载模块

ImportAttribute Record 由以下字段组成:

表 38: ImportAttribute Record 字段
字段名称 值类型 含义
[[Key]] a String 属性键
[[Value]] a String 属性值

16.2.1.3.1 ModuleRequestsEqual ( x, y )

抽象操作 ModuleRequestsEqual,接收参数 x ((ModuleRequest 记录 或 LoadedModuleRequest 记录)) 和 y ((ModuleRequest 记录 或 LoadedModuleRequest 记录));返回值:Boolean。 调用时执行以下步骤:

  1. 如果 x.[[Specifier]] 不是 y.[[Specifier]],则返回 false。
  2. 令 xAttrs 为 x.[[Attributes]]。
  3. 令 yAttrs 为 y.[[Attributes]]。
  4. 令 xAttrsCount 为 xAttrs 中的元素数量。
  5. 令 yAttrsCount 为 yAttrs 中的元素数量。
  6. 如果 xAttrsCount ≠ yAttrsCount,则返回 false。
  7. 对 xAttrs 的每个 ImportAttribute Record xAttr,执行
    1. 如果 yAttrs 不包含某个 ImportAttribute Record yAttr,使得 xAttr.[[Key]] 是 yAttr.[[Key]] 且 xAttr.[[Value]] 是 yAttr.[[Value]],则返回 false。
  8. 返回 true。

16.2.1.4 Static Semantics: ModuleRequests

语法制导操作 ModuleRequests,接收无参数;返回值:列表 (元素:ModuleRequest 记录)。 它按以下产生式分别定义:

Module : [empty]
  1. 返回新的空 List。
ModuleItemList : ModuleItem
  1. 返回 ModuleItem 的 ModuleRequests。
ModuleItemList : ModuleItemList ModuleItem
  1. 令 requests 为 ModuleItemList 的 ModuleRequests。
  2. 令 additionalRequests 为 ModuleItem 的 ModuleRequests。
  3. 对 additionalRequests 的每个 ModuleRequest Record moduleRequest,执行
    1. 如果 requests 不包含某个 ModuleRequest Record otherModuleRequest,使得 ModuleRequestsEqual(moduleRequest, otherModuleRequest) 是 true,则
      1. 将 moduleRequest 追加到 requests。
  4. 返回 requests。
ModuleItem : StatementListItem
  1. 返回新的空 List。
ImportDeclaration : import ImportClause FromClause ;
  1. 令 specifier 为 FromClause 的 SV。
  2. 返回一个 List,其唯一元素是 ModuleRequest Record { [[Specifier]]: specifier, [[Attributes]]: « » }。
ImportDeclaration : import ImportClause FromClause WithClause ;
  1. 令 specifier 为 FromClause 的 SV。
  2. 令 attrs 为 WithClause 的 WithClauseToAttributes。
  3. 返回一个 List,其唯一元素是 ModuleRequest Record { [[Specifier]]: specifier, [[Attributes]]: attrs }。
ImportDeclaration : import ModuleSpecifier ;
  1. 令 specifier 为 ModuleSpecifier 的 SV。
  2. 返回一个 List,其唯一元素是 ModuleRequest Record { [[Specifier]]: specifier, [[Attributes]]: « » }。
ImportDeclaration : import ModuleSpecifier WithClause ;
  1. 令 specifier 为 ModuleSpecifier 的 SV。
  2. 令 attrs 为 WithClause 的 WithClauseToAttributes。
  3. 返回一个 List,其唯一元素是 ModuleRequest Record { [[Specifier]]: specifier, [[Attributes]]: attrs }。
ExportDeclaration : export ExportFromClause FromClause ;
  1. 令 specifier 为 FromClause 的 SV。
  2. 返回一个 List,其唯一元素是 ModuleRequest Record { [[Specifier]]: specifier, [[Attributes]]: « » }。
ExportDeclaration : export ExportFromClause FromClause WithClause ;
  1. 令 specifier 为 FromClause 的 SV。
  2. 令 attrs 为 WithClause 的 WithClauseToAttributes。
  3. 返回一个 List,其唯一元素是 ModuleRequest Record { [[Specifier]]: specifier, [[Attributes]]: attrs }。
ExportDeclaration : export NamedExports ; export VariableStatement export Declaration export default HoistableDeclaration export default ClassDeclaration export default AssignmentExpression ;
  1. 返回新的空 List。

16.2.1.5 抽象 Module Records

Module Record 封装有关单个模块的导入和导出的结构信息。这些信息用于链接一组相互连接模块的导入和导出。Module Record 包含四个仅在模块求值期间使用的字段。

出于规范目的,Module Record 是 Record 规范类型的值,可以将其视为存在于简单的面向对象层次结构中,其中 Module Record 是同时具有抽象子类和具体子类的抽象类。本规范定义名为 Cyclic Module Record 的抽象子类及其名为 Source Text Module Record 的具体子类。其他规范和实现可以定义与它们所定义的替代模块定义设施相对应的其他 Module Record 子类。

Module Record 定义 表 39 中列出的字段。所有 Module Definition 子类至少都包含这些字段。Module Record 还定义 表 40 中的抽象方法列表。所有 Module definition 子类都必须提供这些抽象方法的具体实现。

表 39: Module Record 字段
字段名称 值类型 含义
[[Realm]] a Realm Record 创建此模块的 Realm。
[[Environment]] a Module Environment Record or empty 包含此模块顶层绑定的 Environment Record。此字段在模块链接时设置。
[[Namespace]] an Object or empty 如果已为此模块创建 Module Namespace Object(28.3),则为该对象。
[[HostDefined]] anything (default value is undefined) 保留给需要将附加信息与模块关联的宿主环境使用的字段。
表 40: Module Records的抽象方法
方法 用途 定义
LoadRequestedModules ( [ hostDefined ] )

抽象方法 LoadRequestedModules,接收可选参数 hostDefined (任意值);返回值:Promise。

它通过递归加载模块的所有依赖项,为模块链接做好准备。

在本规范中,它在以下类型中具有定义;宿主可以提供具有其自身定义的其他类型:
GetExportedNames ( [ exportStarSet ] )

抽象方法 GetExportedNames,接收可选参数 exportStarSet (列表 (元素:Source Text Module 记录));返回值:列表 (元素:String)。

它返回直接或间接从此模块导出的所有名称的列表。

调用此方法之前,LoadRequestedModules 必须已成功完成。

在本规范中,它在以下类型中具有定义;宿主可以提供具有其自身定义的其他类型:
ResolveExport ( exportName [ , resolveSet ] )

抽象方法 ResolveExport,接收参数 exportName (String)和可选参数 resolveSet (列表 (元素:记录 (字段:[[Module]] (Module 记录), [[ExportName]] (String))));返回值:(ResolvedBinding 记录、null 或 ambiguous)。

它返回由此模块导出的某个名称的绑定。绑定由形式为 { [[Module]]: Module Record, [[BindingName]]: String | namespace } 的 ResolvedBinding Record 表示。如果导出的是在任何模块中都没有直接绑定的 Module Namespace Object,则 [[BindingName]] 会设置为 namespace。如果无法解析该名称,则返回 null;如果找到多个绑定,则返回 ambiguous。

每次以特定的 exportName、resolveSet 参数对调用此操作时,它都必须返回相同结果。

调用此方法之前,LoadRequestedModules 必须已成功完成。

在本规范中,它在以下类型中具有定义;宿主可以提供具有其自身定义的其他类型:
Evaluate ( )

抽象方法 Evaluate,接收无参数;返回值:Promise。

它返回一个用于此模块及其依赖项求值的 promise;如果求值成功或此前已经成功求值,则该 promise 会兑现;如果发生求值错误或此前已经求值失败,则会拒绝。如果 promise 被拒绝,宿主应处理 promise 拒绝并重新抛出求值错误。除非此模块是 Cyclic Module Record,否则返回的 promise 必须已经 settled。

调用此方法之前,Link 必须已成功完成。

在本规范中,它在以下类型中具有定义;宿主可以提供具有其自身定义的其他类型:

16.2.1.5.1 EvaluateModuleSync ( module )

抽象操作 EvaluateModuleSync,接收参数 module (Module 记录);返回值:(正常完成 (值:unused) 或 抛出完成)。 只要调用方保证 module 的求值会返回已经 settled 的 promise,它就会同步求值 module。 调用时执行以下步骤:

  1. 断言:module 不是 Cyclic Module Record。
  2. 令 promise 为 module.Evaluate()。
  3. 断言:promise.[[PromiseState]] 是 fulfilled 或 rejected。
  4. 如果 promise.[[PromiseState]] 是 rejected,则
    1. 如果 promise.[[PromiseIsHandled]] 是 false,则执行 HostPromiseRejectionTracker(promise, "handle")。
    2. 将 promise.[[PromiseIsHandled]] 设置为 true。
    3. 抛出 promise.[[PromiseResult]]。
  5. 返回 unused。

16.2.1.6 Cyclic Module Records

Cyclic Module Record 用于表示有关模块的信息,该模块可以与 Cyclic Module Record 类型的其他子类模块一起参与依赖循环。不是 Cyclic Module Record 类型子类的 Module Record 不得与 Source Text Module Record 参与依赖循环。

除 表 39 中定义的字段外,Cyclic Module Record 还具有 表 41 中列出的附加字段

表 41: Cyclic Module Records 的附加字段
字段名称 值类型 含义
[[Status]] new, unlinked, linking, linked, evaluating, evaluating-async, or evaluated 初始为 new。随着模块在其生命周期中推进,依次转换为 unlinked、linking、linked、evaluating、可能的 evaluating-async、evaluated。evaluating-async 表示此模块已排队等待其异步依赖项完成后执行,或者它是 [[HasTLA]] 字段为 true、已经执行且正在等待顶层完成的模块。
[[EvaluationError]] a throw completion or empty 表示求值期间发生异常的抛出完成。如果未发生异常,或者 [[Status]] 不是 evaluated,则为 empty。
[[DFSAncestorIndex]] an integer or empty 仅在 Link 和 Evaluate 期间使用的辅助字段。如果 [[Status]] 是 linking 或 evaluating,则它是该模块的深度优先遍历索引,或者同一个强连通分量中某个“更早”模块的深度优先遍历索引。
[[RequestedModules]] a List of ModuleRequest Records 与此模块中的导入关联的 ModuleRequest Record 的 List。该 List 按导入在源文本中的出现顺序排列。
[[LoadedModules]] a List of LoadedModuleRequest Records 从此 record 所表示模块用于请求导入模块的说明符字符串及相应导入属性,到已解析 Module Record 的映射。此列表不包含两个不同的 Record r1 和 r2,使得 ModuleRequestsEqual(r1, r2) 是 true。
[[CycleRoot]] a Cyclic Module Record or empty 循环中第一个被访问的模块,即强连通分量的根 DFS 祖先。对于不在循环中的模块,这就是模块自身。Evaluate 完成后,模块的 [[DFSAncestorIndex]] 是其 [[CycleRoot]] 的深度优先遍历索引。
[[HasTLA]] a Boolean 此模块自身是否为异步模块(例如,它是包含顶层 await 的 Source Text Module Record)。具有异步依赖项并不意味着此字段为 true。模块解析后,此字段不得改变。
[[AsyncEvaluationOrder]] unset, an integer, or done 此字段最初设置为 unset,对于完全同步的模块始终保持 unset。对于自身异步或具有异步依赖项的模块,它会设置为一个整数,用于确定 16.2.1.6.1.3.4 对待执行模块进行排队的顺序。一旦待执行模块成功执行,该字段就设置为 done。
[[TopLevelCapability]] a PromiseCapability Record or empty 如果此模块是某个循环的 [[CycleRoot]],并且对该循环中的某个模块调用了 Evaluate(),则此字段包含整个求值的 PromiseCapability Record。它用于 settle 从 Evaluate() 抽象方法返回的 Promise 对象。对于该模块的任何依赖项,此字段都将为 empty,除非已经为其中某些依赖项启动了顶层 Evaluate()。
[[AsyncParentModules]] a List of Cyclic Module Records 如果此模块或某个依赖项的 [[HasTLA]] 为 true,并且正在执行,则此字段跟踪此模块在顶层执行作业中的父级导入方。这些父模块不会在此模块成功完成执行之前开始执行。
[[PendingAsyncDependencies]] an integer or empty 如果此模块具有任何异步依赖项,则此字段跟踪该模块尚待执行的异步依赖模块数量。当该字段达到 0 且不存在执行错误时,具有异步依赖项的模块将被执行。

除 表 40 中定义的方法外,Cyclic Module Record 还具有 表 42 中列出的附加方法:

表 42: Cyclic Module Records 的附加抽象方法
方法 用途 定义
InitializeEnvironment ( )

抽象方法 InitializeEnvironment,接收无参数;返回值:(正常完成 (值:unused) 或 抛出完成)。

它初始化模块的 Environment Record,包括解析所有导入绑定,并创建模块的执行上下文。
在本规范中,它在以下类型中具有定义;宿主可以提供具有其自身定义的其他类型:
ExecuteModule ( [ capability ] )

抽象方法 ExecuteModule,接收可选参数 capability (PromiseCapability 记录);返回值:(正常完成 (值:unused) 或 抛出完成)。

它在模块的执行上下文中求值模块代码。如果此模块的 [[HasTLA]] 为 true,则会将 PromiseCapability Record 作为参数传入,并且该方法应兑现或拒绝给定的 capability。在这种情况下,该方法不得抛出异常,而应在必要时拒绝 PromiseCapability Record。
在本规范中,它在以下类型中具有定义;宿主可以提供具有其自身定义的其他类型:

GraphLoadingState Record 是包含模块图加载过程相关信息的 Record。它用于在调用 HostLoadImportedModule 后继续加载。每个 GraphLoadingState Record 都具有 表 43 中定义的字段:

表 43: GraphLoadingState Record 字段
字段名称 值类型 含义
[[PromiseCapability]] a PromiseCapability Record 加载过程完成时要兑现的 promise。
[[IsLoading]] a Boolean 如果加载过程尚未完成,无论是成功还是出错,则为 true。
[[PendingModulesCount]] a non-negative integer 它跟踪待处理的 HostLoadImportedModule 调用数量。
[[Visited]] a List of Cyclic Module Records 它是当前加载过程中已经加载的 Cyclic Module Record 列表,用于避免循环依赖造成无限循环。
[[HostDefined]] anything (default value is empty) 它包含要从 LoadRequestedModules 调用方传递给 HostLoadImportedModule 的宿主定义数据。

16.2.1.6.1 Module Record 抽象方法的实现

以下是 Cyclic Module Record 的具体方法,它们实现 表 40 中定义的相应 Module Record 抽象方法。

16.2.1.6.1.1 LoadRequestedModules ( [ hostDefined ] )

a Cyclic Module Record module的具体方法 LoadRequestedModules,接收可选参数 hostDefined (任意值);返回值:Promise。 它填充 module 依赖图中所有 Module Record 的 [[LoadedModules]](大部分工作由辅助函数 InnerModuleLoading 完成)。它接受一个可选的 hostDefined 参数,该参数会传递给 HostLoadImportedModule 钩子。 调用时执行以下步骤:

  1. 如果不存在 hostDefined,则将 hostDefined 设置为 empty。
  2. 令 promiseCapability 为 ! NewPromiseCapability(%Promise%)。
  3. 令 state 为 GraphLoadingState Record { [[IsLoading]]: true, [[PendingModulesCount]]: 1, [[Visited]]: « », [[PromiseCapability]]: promiseCapability, [[HostDefined]]: hostDefined }。
  4. 执行 InnerModuleLoading(state, module)。
  5. 返回 promiseCapability.[[Promise]]。
注
hostDefined 参数可以用于传递获取所导入模块所需的附加信息。例如,HTML 使用它为 <link rel="preload" as="..."> 标签设置正确的 fetch destination。 import() 表达式绝不会设置 hostDefined 参数。

16.2.1.6.1.1.1 InnerModuleLoading ( state, module )

抽象操作 InnerModuleLoading,接收参数 state (GraphLoadingState 记录) 和 module (Module 记录);返回值:unused。 LoadRequestedModules 使用它递归执行 module 依赖图的实际加载过程。 调用时执行以下步骤:

  1. 断言:state.[[IsLoading]] 是 true。
  2. 如果 module 是 Cyclic Module Record,module.[[Status]] 是 new,并且 state.[[Visited]] 不包含 module,则
    1. 将 module 追加到 state.[[Visited]]。
    2. 令 requestedModulesCount 为 module.[[RequestedModules]] 中的元素数量。
    3. 将 state.[[PendingModulesCount]] 设置为 state.[[PendingModulesCount]] + requestedModulesCount。
    4. 对 module.[[RequestedModules]] 的每个 ModuleRequest Record request,执行
      1. 如果 AllImportAttributesSupported(request.[[Attributes]]) 是 false,则
        1. 令 error 为 ThrowCompletion(新创建的 SyntaxError 对象)。
        2. 执行 ContinueModuleLoading(state, error)。
      2. 否则如果 module.[[LoadedModules]] 包含某个 LoadedModuleRequest Record record,使得 ModuleRequestsEqual(record, request) 是 true,则
        1. 执行 InnerModuleLoading(state, record.[[Module]])。
      3. 否则,
        1. 执行 HostLoadImportedModule(module, request, state.[[HostDefined]], state)。
        2. 注:HostLoadImportedModule 将调用 FinishLoadingImportedModule,后者通过 ContinueModuleLoading 重新进入图加载过程。
      4. 如果 state.[[IsLoading]] 是 false,则返回 unused。
  3. 断言:state.[[PendingModulesCount]] ≥ 1。
  4. 将 state.[[PendingModulesCount]] 设置为 state.[[PendingModulesCount]] - 1。
  5. 如果 state.[[PendingModulesCount]] = 0,则
    1. 将 state.[[IsLoading]] 设置为 false。
    2. 对 state.[[Visited]] 的每个 Cyclic Module Record loaded,执行
      1. 如果 loaded.[[Status]] 是 new,则将 loaded.[[Status]] 设置为 unlinked。
    3. 执行 ! Call(state.[[PromiseCapability]].[[Resolve]], undefined, « undefined »)。
  6. 返回 unused。

16.2.1.6.1.1.2 ContinueModuleLoading ( state, moduleCompletion )

抽象操作 ContinueModuleLoading,接收参数 state (GraphLoadingState 记录) 和 moduleCompletion ((正常完成 (值:Module 记录) 或 抛出完成));返回值:unused。 它用于在调用 HostLoadImportedModule 后重新进入加载过程。 调用时执行以下步骤:

  1. 如果 state.[[IsLoading]] 是 false,则返回 unused。
  2. 如果 moduleCompletion 是正常完成,则
    1. 执行 InnerModuleLoading(state, moduleCompletion.[[Value]])。
  3. 否则,
    1. 将 state.[[IsLoading]] 设置为 false。
    2. 执行 ! Call(state.[[PromiseCapability]].[[Reject]], undefined, « moduleCompletion.[[Value]] »)。
  4. 返回 unused。

16.2.1.6.1.2 Link ( )

a Cyclic Module Record module的具体方法 Link,接收无参数;返回值:(正常完成 (值:unused) 或 抛出完成)。 成功时,Link 会将此模块的 [[Status]] 从 unlinked 转换为 linked。失败时,会抛出异常,并且此模块的 [[Status]] 保持为 unlinked。(大部分工作由辅助函数 InnerModuleLinking 完成。) 调用时执行以下步骤:

  1. 断言:module.[[Status]] 是 unlinked、linked、evaluating-async 或 evaluated 之一。
  2. 令 stack 为新的空 List。
  3. 令 result 为 Completion(InnerModuleLinking(module, stack, 0))。
  4. 如果 result 是突然完成,则
    1. 对 stack 的每个 Cyclic Module Record requiredModule,执行
      1. 断言:requiredModule.[[Status]] 是 linking。
      2. 将 requiredModule.[[Status]] 设置为 unlinked。
    2. 断言:module.[[Status]] 是 unlinked。
    3. 返回 ? result。
  5. 断言:module.[[Status]] 是 linked、evaluating-async 或 evaluated 之一。
  6. 断言:stack 为空。
  7. 返回 unused。

16.2.1.6.1.2.1 InnerModuleLinking ( module, stack, index )

抽象操作 InnerModuleLinking,接收参数 module (Module 记录)、stack (列表 (元素:Cyclic Module 记录)) 和 index (非负整数);返回值:(正常完成 (值:非负整数) 或 抛出完成)。 Link 使用它为 module 执行实际链接过程,并递归处理依赖图中的所有其他模块。stack 和 index 参数以及模块的 [[DFSAncestorIndex]] 字段用于跟踪深度优先搜索(DFS)遍历。具体来说,[[DFSAncestorIndex]] 用于发现强连通分量(SCC),使得一个 SCC 中的所有模块一起转换到 linked。 调用时执行以下步骤:

  1. 如果 module 不是 Cyclic Module Record,则
    1. 执行 ? module.Link()。
    2. 返回 index。
  2. 如果 module.[[Status]] 是 linking、linked、evaluating-async 或 evaluated 之一,则
    1. 返回 index。
  3. 断言:module.[[Status]] 是 unlinked。
  4. 将 module.[[Status]] 设置为 linking。
  5. 令 moduleIndex 为 index。
  6. 将 module.[[DFSAncestorIndex]] 设置为 index。
  7. 将 index 设置为 index + 1。
  8. 将 module 追加到 stack。
  9. 对 module.[[RequestedModules]] 的每个 ModuleRequest Record request,执行
    1. 令 requiredModule 为 GetImportedModule(module, request)。
    2. 将 index 设置为 ? InnerModuleLinking(requiredModule, stack, index)。
    3. 如果 requiredModule 是 Cyclic Module Record,则
      1. 断言:requiredModule.[[Status]] 是 linking、linked、evaluating-async 或 evaluated 之一。
      2. 断言:requiredModule.[[Status]] 是 linking,当且仅当 stack 包含 requiredModule。
      3. 如果 requiredModule.[[Status]] 是 linking,则
        1. 将 module.[[DFSAncestorIndex]] 设置为 min(module.[[DFSAncestorIndex]], requiredModule.[[DFSAncestorIndex]])。
  10. 执行 ? module.InitializeEnvironment()。
  11. 断言:module 在 stack 中恰好出现一次。
  12. 断言:module.[[DFSAncestorIndex]] ≤ moduleIndex。
  13. 如果 module.[[DFSAncestorIndex]] = moduleIndex,则
    1. 令 done 为 false。
    2. 当 done 是 false 时,重复执行,
      1. 令 requiredModule 为 stack 的最后一个元素。
      2. 从 stack 中移除最后一个元素。
      3. 断言:requiredModule 是 Cyclic Module Record。
      4. 将 requiredModule.[[Status]] 设置为 linked。
      5. 如果 requiredModule 和 module 是同一个 Module Record,则将 done 设置为 true。
  14. 返回 index。

16.2.1.6.1.3 Evaluate ( )

a Cyclic Module Record module的具体方法 Evaluate,接收无参数;返回值:Promise。 Evaluate 会将此模块的 [[Status]] 从 linked 转换为 evaluating-async 或 evaluated。首次对给定强连通分量中的某个模块调用它时,Evaluate 会创建并返回一个 Promise,该 Promise 会在模块完成求值时兑现。此 Promise 存储在该分量 [[CycleRoot]] 的 [[TopLevelCapability]] 字段中。以后对该分量中任何模块调用 Evaluate 都会返回同一个 Promise。(大部分工作由辅助函数 InnerModuleEvaluation 完成。) 调用时执行以下步骤:

  1. 断言:此 Evaluate 调用没有与周围代理中的另一个 Evaluate 调用同时发生。
  2. 断言:module.[[Status]] 是 linked、evaluating-async 或 evaluated 之一。
  3. 如果 module.[[Status]] 是 evaluating-async 或 evaluated,则
    1. 如果 module.[[CycleRoot]] 不是 empty,则
      1. 将 module 设置为 module.[[CycleRoot]]。
    2. 否则,
      1. 断言:module.[[Status]] 是 evaluated,并且 module.[[EvaluationError]] 是抛出完成。
  4. 如果 module.[[TopLevelCapability]] 不是 empty,则
    1. 返回 module.[[TopLevelCapability]].[[Promise]]。
  5. 令 stack 为新的空 List。
  6. 令 promiseCapability 为 ! NewPromiseCapability(%Promise%)。
  7. 将 module.[[TopLevelCapability]] 设置为 promiseCapability。
  8. 令 result 为 Completion(InnerModuleEvaluation(module, stack, 0))。
  9. 如果 result 是突然完成,则
    1. 对 stack 的每个 Cyclic Module Record requiredModule,执行
      1. 断言:requiredModule.[[Status]] 是 evaluating。
      2. 将 requiredModule.[[Status]] 设置为 evaluated。
      3. 将 requiredModule.[[EvaluationError]] 设置为 result。
    2. 断言:module.[[Status]] 是 evaluated。
    3. 断言:module.[[EvaluationError]] 和 result 是同一个 Completion Record。
    4. 执行 ! Call(promiseCapability.[[Reject]], undefined, « result.[[Value]] »)。
  10. 否则,
    1. 断言:module.[[Status]] 是 evaluating-async 或 evaluated。
    2. 断言:module.[[EvaluationError]] 是 empty。
    3. 如果 module.[[Status]] 是 evaluated,则
      1. 断言:module.[[AsyncEvaluationOrder]] 是 unset 或 done。
      2. 注:当且仅当 module 此前已经求值且该求值是异步的,module.[[AsyncEvaluationOrder]] 才是 done。
      3. 执行 ! Call(promiseCapability.[[Resolve]], undefined, « undefined »)。
    4. 断言:stack 为空。
  11. 返回 promiseCapability.[[Promise]]。

16.2.1.6.1.3.1 InnerModuleEvaluation ( module, stack, index )

抽象操作 InnerModuleEvaluation,接收参数 module (Module 记录)、stack (列表 (元素:Cyclic Module 记录)) 和 index (非负整数);返回值:(正常完成 (值:非负整数) 或 抛出完成)。 Evaluate 使用它为 module 执行实际求值过程,并递归处理依赖图中的所有其他模块。stack 和 index 参数以及 module 的 [[DFSAncestorIndex]] 字段的使用方式与 InnerModuleLinking 中相同。 调用时执行以下步骤:

  1. 如果 module 不是 Cyclic Module Record,则
    1. 执行 ? EvaluateModuleSync(module)。
    2. 返回 index。
  2. 如果 module.[[Status]] 是 evaluating-async 或 evaluated,则
    1. 如果 module.[[EvaluationError]] 是 empty,则返回 index。
    2. 返回 ? module.[[EvaluationError]]。
  3. 如果 module.[[Status]] 是 evaluating,则返回 index。
  4. 断言:module.[[Status]] 是 linked。
  5. 将 module.[[Status]] 设置为 evaluating。
  6. 令 moduleIndex 为 index。
  7. 将 module.[[DFSAncestorIndex]] 设置为 index。
  8. 将 module.[[PendingAsyncDependencies]] 设置为 0。
  9. 将 index 设置为 index + 1。
  10. 将 module 追加到 stack。
  11. 对 module.[[RequestedModules]] 的每个 ModuleRequest Record request,执行
    1. 令 requiredModule 为 GetImportedModule(module, request)。
    2. 将 index 设置为 ? InnerModuleEvaluation(requiredModule, stack, index)。
    3. 如果 requiredModule 是 Cyclic Module Record,则
      1. 断言:requiredModule.[[Status]] 是 evaluating、evaluating-async 或 evaluated 之一。
      2. 断言:requiredModule.[[Status]] 是 evaluating,当且仅当 stack 包含 requiredModule。
      3. 如果 requiredModule.[[Status]] 是 evaluating,则
        1. 将 module.[[DFSAncestorIndex]] 设置为 min(module.[[DFSAncestorIndex]], requiredModule.[[DFSAncestorIndex]])。
      4. 否则,
        1. 将 requiredModule 设置为 requiredModule.[[CycleRoot]]。
        2. 断言:requiredModule.[[Status]] 是 evaluating-async 或 evaluated。
        3. 如果 requiredModule.[[EvaluationError]] 不是 empty,则返回 ? requiredModule.[[EvaluationError]]。
      5. 如果 requiredModule.[[AsyncEvaluationOrder]] 是整数,则
        1. 将 module.[[PendingAsyncDependencies]] 设置为 module.[[PendingAsyncDependencies]] + 1。
        2. 将 module 追加到 requiredModule.[[AsyncParentModules]]。
  12. 如果 module.[[HasTLA]] 是 true 或 module.[[PendingAsyncDependencies]] > 0,则
    1. 断言:module.[[AsyncEvaluationOrder]] 是 unset。
    2. 将 module.[[AsyncEvaluationOrder]] 设置为 IncrementModuleAsyncEvaluationCount()。
    3. 如果 module.[[PendingAsyncDependencies]] = 0,则执行 ExecuteAsyncModule(module)。
  13. 否则,
    1. 执行 ? module.ExecuteModule()。
  14. 断言:module 在 stack 中恰好出现一次。
  15. 断言:module.[[DFSAncestorIndex]] ≤ moduleIndex。
  16. 如果 module.[[DFSAncestorIndex]] = moduleIndex,则
    1. 令 done 为 false。
    2. 当 done 是 false 时,重复执行,
      1. 令 requiredModule 为 stack 的最后一个元素。
      2. 从 stack 中移除最后一个元素。
      3. 断言:requiredModule 是 Cyclic Module Record。
      4. 断言:requiredModule.[[AsyncEvaluationOrder]] 是整数或 unset。
      5. 如果 requiredModule.[[AsyncEvaluationOrder]] 是 unset,则将 requiredModule.[[Status]] 设置为 evaluated。
      6. 否则,将 requiredModule.[[Status]] 设置为 evaluating-async。
      7. 如果 requiredModule 和 module 是同一个 Module Record,则将 done 设置为 true。
      8. 将 requiredModule.[[CycleRoot]] 设置为 module。
  17. 返回 index。
注 1

当 InnerModuleEvaluation 正在遍历模块时,该模块处于 evaluating。模块在执行完成时处于 evaluated;如果其 [[HasTLA]] 字段为 true 或具有异步依赖项,则在执行期间处于 evaluating-async。

注 2

当异步循环中的模块不处于 evaluating 时,依赖该模块的任何模块将改为通过 [[CycleRoot]] 依赖循环根的执行。这样可确保通过根模块状态将循环状态视为单个强连通分量。

16.2.1.6.1.3.2 ExecuteAsyncModule ( module )

抽象操作 ExecuteAsyncModule,接收参数 module (Cyclic Module 记录);返回值:unused。 调用时执行以下步骤:

  1. 断言:module.[[Status]] 是 evaluating 或 evaluating-async。
  2. 断言:module.[[HasTLA]] 是 true。
  3. 令 promiseCapability 为 ! NewPromiseCapability(%Promise%)。
  4. 令 fulfilledClosure 为一个没有参数的新 Abstract Closure,它捕获 module,并在被调用时执行以下步骤:
    1. 执行 AsyncModuleExecutionFulfilled(module)。
    2. 返回 NormalCompletion(undefined)。
  5. 令 onFulfilled 为 CreateBuiltinFunction(fulfilledClosure, 0, "", « »)。
  6. 令 rejectedClosure 为一个具有参数 (error) 的新 Abstract Closure,它捕获 module,并在被调用时执行以下步骤:
    1. 执行 AsyncModuleExecutionRejected(module, error)。
    2. 返回 NormalCompletion(undefined)。
  7. 令 onRejected 为 CreateBuiltinFunction(rejectedClosure, 0, "", « »)。
  8. 执行 PerformPromiseThen(promiseCapability.[[Promise]], onFulfilled, onRejected)。
  9. 执行 ! module.ExecuteModule(promiseCapability)。
  10. 返回 unused。

16.2.1.6.1.3.3 GatherAvailableAncestors ( module, execList )

抽象操作 GatherAvailableAncestors,接收参数 module (Cyclic Module 记录) 和 execList (列表 (元素:Cyclic Module 记录));返回值:unused。 调用时执行以下步骤:

  1. 对 module.[[AsyncParentModules]] 的每个 Cyclic Module Record ancestorModule,执行
    1. 如果 execList 不包含 ancestorModule,并且 ancestorModule.[[CycleRoot]].[[EvaluationError]] 是 empty,则
      1. 断言:ancestorModule.[[Status]] 是 evaluating-async。
      2. 断言:ancestorModule.[[EvaluationError]] 是 empty。
      3. 断言:ancestorModule.[[AsyncEvaluationOrder]] 是整数。
      4. 断言:ancestorModule.[[PendingAsyncDependencies]] > 0。
      5. 将 ancestorModule.[[PendingAsyncDependencies]] 设置为 ancestorModule.[[PendingAsyncDependencies]] - 1。
      6. 如果 ancestorModule.[[PendingAsyncDependencies]] = 0,则
        1. 将 ancestorModule 追加到 execList。
        2. 如果 ancestorModule.[[HasTLA]] 是 false,则执行 GatherAvailableAncestors(ancestorModule, execList)。
  2. 返回 unused。
注

当根 module 的异步执行兑现时,此函数确定可在该完成时一起同步执行的模块列表,并将它们填充到 execList 中。

16.2.1.6.1.3.4 AsyncModuleExecutionFulfilled ( module )

抽象操作 AsyncModuleExecutionFulfilled,接收参数 module (Cyclic Module 记录);返回值:unused。 调用时执行以下步骤:

  1. 如果 module.[[Status]] 是 evaluated,则
    1. 断言:module.[[EvaluationError]] 不是 empty。
    2. 返回 unused。
  2. 断言:module.[[Status]] 是 evaluating-async。
  3. 断言:module.[[AsyncEvaluationOrder]] 是整数。
  4. 断言:module.[[EvaluationError]] 是 empty。
  5. 将 module.[[AsyncEvaluationOrder]] 设置为 done。
  6. 将 module.[[Status]] 设置为 evaluated。
  7. 如果 module.[[TopLevelCapability]] 不是 empty,则
    1. 断言:module.[[CycleRoot]] 和 module 是同一个 Module Record。
    2. 执行 ! Call(module.[[TopLevelCapability]].[[Resolve]], undefined, « undefined »)。
  8. 令 execList 为新的空 List。
  9. 执行 GatherAvailableAncestors(module, execList)。
  10. 断言:execList 的所有元素的 [[AsyncEvaluationOrder]] 字段都设置为整数,[[PendingAsyncDependencies]] 字段设置为 0,且 [[EvaluationError]] 字段设置为 empty。
  11. 令 sortedExecList 为一个 List,其元素是 execList 的元素,并按其 [[AsyncEvaluationOrder]] 字段升序排序。
  12. 对 sortedExecList 的每个 Cyclic Module Record ancestorModule,执行
    1. 如果 ancestorModule.[[Status]] 是 evaluated,则
      1. 断言:ancestorModule.[[EvaluationError]] 不是 empty。
    2. 否则如果 ancestorModule.[[HasTLA]] 是 true,则
      1. 执行 ExecuteAsyncModule(ancestorModule)。
    3. 否则,
      1. 令 result 为 Completion(ancestorModule.ExecuteModule())。
      2. 如果 result 是突然完成,则
        1. 执行 AsyncModuleExecutionRejected(ancestorModule, result.[[Value]])。
      3. 否则,
        1. 将 ancestorModule.[[AsyncEvaluationOrder]] 设置为 done。
        2. 将 ancestorModule.[[Status]] 设置为 evaluated。
        3. 如果 ancestorModule.[[TopLevelCapability]] 不是 empty,则
          1. 断言:ancestorModule.[[CycleRoot]] 和 ancestorModule 是同一个 Module Record。
          2. 执行 ! Call(ancestorModule.[[TopLevelCapability]].[[Resolve]], undefined, « undefined »)。
  13. 返回 unused。

16.2.1.6.1.3.5 AsyncModuleExecutionRejected ( module, error )

抽象操作 AsyncModuleExecutionRejected,接收参数 module (Cyclic Module 记录) 和 error (ECMAScript 语言值);返回值:unused。 调用时执行以下步骤:

  1. 如果 module.[[Status]] 是 evaluated,则
    1. 断言:module.[[EvaluationError]] 不是 empty。
    2. 返回 unused。
  2. 断言:module.[[Status]] 是 evaluating-async。
  3. 断言:module.[[AsyncEvaluationOrder]] 是整数。
  4. 断言:module.[[EvaluationError]] 是 empty。
  5. 将 module.[[EvaluationError]] 设置为 ThrowCompletion(error)。
  6. 将 module.[[Status]] 设置为 evaluated。
  7. 将 module.[[AsyncEvaluationOrder]] 设置为 done。
  8. 注:module.[[AsyncEvaluationOrder]] 被设置为 done,以与 AsyncModuleExecutionFulfilled 保持对称。在 InnerModuleEvaluation 中,当模块的 [[EvaluationError]] 内部槽不是 empty 时,不使用其 [[AsyncEvaluationOrder]] 内部槽的值。
  9. 如果 module.[[TopLevelCapability]] 不是 empty,则
    1. 断言:module.[[CycleRoot]] 和 module 是同一个 Module Record。
    2. 执行 ! Call(module.[[TopLevelCapability]].[[Reject]], undefined, « error »)。
  10. 对 module.[[AsyncParentModules]] 的每个 Cyclic Module Record ancestorModule,执行
    1. 执行 AsyncModuleExecutionRejected(ancestorModule, error)。
  11. 返回 unused。

16.2.1.6.2 Cyclic Module Record 图示例

本非规范性章节给出几个常见模块图的链接和求值示例,重点说明错误可能如何发生。

首先考虑以下简单模块图:

图 2: 一个简单的模块图
一个模块图,其中模块 A 依赖模块 B,而模块 B 依赖模块 C

首先假设不存在错误条件。当宿主首次调用 A.LoadRequestedModules() 时,根据假设,该调用会成功完成,并递归加载 B 和 C 的依赖项(分别为 C 和无),然后将 A.[[Status]] = B.[[Status]] = C.[[Status]] = unlinked。随后,当宿主调用 A.Link() 时,它也会成功完成(同样根据假设),使得 A.[[Status]] = B.[[Status]] = C.[[Status]] = linked。这些准备步骤可以在任何时间执行。之后,当宿主准备承担模块可能产生的任何副作用时,它可以调用 A.Evaluate(),该调用会成功完成,返回一个兑现为 undefined 的 Promise(同样根据假设),并递归地先求值 C,再求值 B。此时每个模块的 [[Status]] 都将是 evaluated。

接下来考虑在成功调用 A.LoadRequestedModules() 后发生链接错误的情况。如果 C 的 InnerModuleLinking 成功,但随后 B 失败,例如因为它导入了 C 未提供的内容,则最初的 A.Link() 将失败,并且 A 和 B 的 [[Status]] 都保持为 unlinked。不过,C 的 [[Status]] 已经变为 linked。

最后,考虑在成功调用 Link() 后发生求值错误的情况。如果 C 的 InnerModuleEvaluation 成功,但随后 B 失败,例如因为 B 包含抛出异常的代码,则最初的 A.Evaluate() 将失败,并返回被拒绝的 Promise。产生的异常会记录在 A 和 B 的 [[EvaluationError]] 字段中,它们的 [[Status]] 将变为 evaluated。C 也会变为 evaluated,但与 A 和 B 不同,由于其成功完成求值,它仍然没有 [[EvaluationError]]。存储该异常可确保宿主以后每次尝试通过调用 Evaluate() 方法重用 A 或 B 时,都会遇到同一个异常。(宿主不要求重用 Cyclic Module Record;同样,宿主也不要求暴露这些方法抛出的异常对象。不过,本规范允许此类用途。)

现在考虑另一种错误条件:

图 3: 包含无法解析模块的模块图
一个模块图,其中模块 A 依赖一个缺失(无法解析)的模块,以 ??? 表示

在这种场景中,模块 A 声明对另一个模块的依赖,但该模块不存在 Module Record,也就是说,当 HostLoadImportedModule 被要求加载它时,会以异常调用 FinishLoadingImportedModule。出现这种情况可能有多种原因,例如对应资源不存在,或者资源存在,但尝试解析所得源文本时 ParseModule 返回了一些错误。宿主可以选择通过传递给 FinishLoadingImportedModule 的完成来暴露失败原因。无论如何,此异常都会导致加载失败,使得 A 的 [[Status]] 保持为 new。

这里加载、链接和求值错误之间的差异源于以下特性:

  • 求值只能执行一次,因为它可能产生副作用;因此,即使求值失败,也必须记住是否已经执行过求值。(在错误情况下,同时记住异常也很合理,否则后续 Evaluate() 调用将不得不合成一个新的异常。)
  • 另一方面,链接没有副作用,因此即使失败,也可以在以后重试而不会产生问题。
  • 加载与宿主密切交互,并且某些宿主可能希望允许用户重试失败的加载(例如,如果失败是由暂时不良的网络状况引起的)。

现在,考虑具有循环的模块图:

图 4: 循环模块图
一个模块图,其中模块 A 依赖模块 B 和 C,而模块 B 也依赖模块 A

这里假设入口点是模块 A,因此宿主首先调用 A.LoadRequestedModules(),该调用对 A 执行 InnerModuleLoading。随后又对 B 和 C 调用 InnerModuleLoading。由于存在循环,这再次触发对 A 的 InnerModuleLoading,但此时它不执行任何操作,因为在此次 LoadRequestedModules 过程中,A 的依赖项加载已经被触发。当图中的所有模块都成功加载后,它们的 [[Status]] 会同时从 new 转换为 unlinked。

随后,宿主调用 A.Link(),该调用对 A 执行 InnerModuleLinking。接着对 B 执行 InnerModuleLinking。由于存在循环,这再次触发对 A 的 InnerModuleLinking,但此时它不执行任何操作,因为 A.[[Status]] 已经是 linking。当控制返回 A 并对 C 触发 InnerModuleLinking 时,B.[[Status]] 自身仍保持 linking。当此次调用返回并且 C.[[Status]] 为 linked 后,A 和 B 会一起从 linking 转换为 linked;这是有意设计的,因为它们构成一个强连通分量。之所以能够同时转换同一个 SCC 中模块的状态,是因为在这一阶段会使用深度优先搜索遍历模块图。

在成功情况下,循环模块图的求值阶段会发生类似的过程。

现在考虑 A 存在链接错误的情况;例如,它试图从 C 导入一个不存在的绑定。在这种情况下,上述步骤仍然会发生,包括第二次对 A 调用 InnerModuleLinking 时提前返回。不过,一旦我们展开回最初对 A 的 InnerModuleLinking,它就会在 InitializeEnvironment 期间失败,也就是紧接在 C.ResolveExport() 之后。抛出的 SyntaxError 异常会向上传播到 A.Link,后者会重置当前位于其 stack 上的所有模块(这些模块始终恰好是仍处于 linking 的模块)。因此,A 和 B 都会变为 unlinked。注意,C 仍保持 linked。

或者,考虑 A 存在求值错误的情况;例如,其源代码抛出异常。在这种情况下,与上述步骤对应的求值阶段仍然会发生,包括第二次对 A 调用 InnerModuleEvaluation 时提前返回。不过,一旦我们展开回最初对 A 的 InnerModuleEvaluation,根据假设它会失败。抛出的异常会向上传播到 A.Evaluate(),后者会在当前位于其 stack 上的所有模块(即仍处于 evaluating 的模块)中记录该错误;对于整个依赖图中包含顶层 await 或依赖顶层 await 的模块,还会通过 [[AsyncParentModules]] 以及 AsyncModuleExecutionRejected 算法形成的链传播。因此,A 和 B 都会变为 evaluated,并且异常会记录在 A 和 B 的 [[EvaluationError]] 字段中,而 C 保持为 evaluated 且没有 [[EvaluationError]]。

最后,考虑一个具有循环、且所有模块都异步完成的模块图:

图 5: 异步循环模块图
一个模块图,其中模块 A 依赖模块 B 和 C,模块 B 依赖模块 D,模块 C 依赖模块 D 和 E,而模块 D 依赖模块 A

加载和链接与之前一样发生,最终所有模块的 [[Status]] 都设置为 linked。

调用 A.Evaluate() 会对 A、B 和 D 调用 InnerModuleEvaluation,它们都会转换为 evaluating。随后再次对 A 调用 InnerModuleEvaluation,由于它已经是 evaluating,因此不执行任何操作。此时,D.[[PendingAsyncDependencies]] 为 0,所以调用 ExecuteAsyncModule(D),并使用一个新的 PromiseCapability 调用 D.ExecuteModule,以跟踪 D 的异步执行。我们展开回 B 的 InnerModuleEvaluation,将 B.[[PendingAsyncDependencies]] 设置为 1,并将 B.[[AsyncEvaluationOrder]] 设置为 1。然后展开回最初对 A 的 InnerModuleEvaluation,将 A.[[PendingAsyncDependencies]] 设置为 1。在遍历 A 依赖项的下一次循环迭代中,我们对 C 调用 InnerModuleEvaluation,从而又对 D(再次不执行任何操作)和 E 调用。由于 E 没有依赖项且不属于循环,因此我们以与 D 相同的方式调用 ExecuteAsyncModule(E),并立即将 E 从栈中移除。我们再次展开回 C 的 InnerModuleEvaluation,将 C.[[AsyncEvaluationOrder]] 设置为 3。现在我们完成对 A 依赖项的循环,将 A.[[AsyncEvaluationOrder]] 设置为 4,并从栈中移除整个强连通分量,同时将所有模块一次性转换为 evaluating-async。此时,模块字段如 表 44 所示。

表 44: 初始 Evaluate() 调用后的模块字段
字段
模块
A B C D E
[[DFSAncestorIndex]] 0 0 0 0 4
[[Status]] evaluating-async evaluating-async evaluating-async evaluating-async evaluating-async
[[AsyncEvaluationOrder]] 4 1 3 0 2
[[AsyncParentModules]] « » « A » « A » « B, C » « C »
[[PendingAsyncDependencies]] 2 (B 和 C) 1 (D) 2 (D 和 E) 0 0

假设 E 首先完成执行。发生这种情况时,会调用 AsyncModuleExecutionFulfilled,E.[[Status]] 设置为 evaluated,并将 C.[[PendingAsyncDependencies]] 递减为 1。更新后的模块字段如 表 45 所示。

表 45: 模块 E 完成执行后的模块字段
字段
模块
C E
[[DFSAncestorIndex]] 0 4
[[Status]] evaluating-async evaluated
[[AsyncEvaluationOrder]] 3 done
[[AsyncParentModules]] « A » « C »
[[PendingAsyncDependencies]] 1 (D) 0

接下来 D 完成执行(因为它是唯一仍在执行的模块)。发生这种情况时,再次调用 AsyncModuleExecutionFulfilled,并将 D.[[Status]] 设置为 evaluated。可供执行的祖先是 B(其 [[AsyncEvaluationOrder]] 为 1)和 C(其 [[AsyncEvaluationOrder]] 为 3),因此会首先处理 B:将 B.[[PendingAsyncDependencies]] 递减为 0,对 B 调用 ExecuteAsyncModule,并开始执行。C.[[PendingAsyncDependencies]] 也递减为 0,C 开始执行(如果 B 包含 await,则可能与 B 并行执行)。更新后的模块字段如 表 46 所示。

表 46: 模块 D 完成执行后的模块字段
字段
模块
B C D
[[DFSAncestorIndex]] 0 0 0
[[Status]] evaluating-async evaluating-async evaluated
[[AsyncEvaluationOrder]] 1 3 done
[[AsyncParentModules]] « A » « A » « B, C »
[[PendingAsyncDependencies]] 0 0 0

假设接下来 C 完成执行。发生这种情况时,再次调用 AsyncModuleExecutionFulfilled,C.[[Status]] 设置为 evaluated,并将 A.[[PendingAsyncDependencies]] 递减为 1。更新后的模块字段如 表 47 所示。

表 47: 模块 C 完成执行后的模块字段
字段
模块
A C
[[DFSAncestorIndex]] 0 0
[[Status]] evaluating-async evaluated
[[AsyncEvaluationOrder]] 4 done
[[AsyncParentModules]] « » « A »
[[PendingAsyncDependencies]] 1 (B) 0

然后,B 完成执行。发生这种情况时,再次调用 AsyncModuleExecutionFulfilled,并将 B.[[Status]] 设置为 evaluated。A.[[PendingAsyncDependencies]] 递减为 0,因此调用 ExecuteAsyncModule,A 开始执行。更新后的模块字段如 表 48 所示。

表 48: 模块 B 完成执行后的模块字段
字段
模块
A B
[[DFSAncestorIndex]] 0 0
[[Status]] evaluating-async evaluated
[[AsyncEvaluationOrder]] 4 done
[[AsyncParentModules]] « » « A »
[[PendingAsyncDependencies]] 0 0

最后,A 完成执行。发生这种情况时,再次调用 AsyncModuleExecutionFulfilled,并将 A.[[Status]] 设置为 evaluated。此时,A.[[TopLevelCapability]] 中的 Promise(它由 A.Evaluate() 返回)会被兑现,从而结束对该模块图的处理。更新后的模块字段如 表 49 所示。

表 49: 模块 A 完成执行后的模块字段
字段
模块
A
[[DFSAncestorIndex]] 0
[[Status]] evaluated
[[AsyncEvaluationOrder]] done
[[AsyncParentModules]] « »
[[PendingAsyncDependencies]] 0

或者,考虑失败情况:C 执行失败,并在 B 完成执行之前返回错误。发生这种情况时,会调用 AsyncModuleExecutionRejected,将 C.[[Status]] 设置为 evaluated,并将 C.[[EvaluationError]] 设置为该错误。然后,它通过对所有 AsyncParentModules 执行 AsyncModuleExecutionRejected,将此错误传播给它们。更新后的模块字段如 表 50 所示。

表 50: 模块 C 以错误结束后的模块字段
字段
模块
A C
[[DFSAncestorIndex]] 0 0
[[Status]] evaluated evaluated
[[AsyncEvaluationOrder]] done done
[[AsyncParentModules]] « » « A »
[[PendingAsyncDependencies]] 1 (B) 0
[[EvaluationError]] empty C 的求值错误

A 将以与 C 相同的错误被拒绝,因为 C 会以 C 的错误对 A 调用 AsyncModuleExecutionRejected。A.[[Status]] 设置为 evaluated。此时,A.[[TopLevelCapability]] 中的 Promise(它由 A.Evaluate() 返回)被拒绝。更新后的模块字段如 表 51 所示。

表 51: 模块 A 被拒绝后的模块字段
字段
模块
A
[[DFSAncestorIndex]] 0
[[Status]] evaluated
[[AsyncEvaluationOrder]] done
[[AsyncParentModules]] « »
[[PendingAsyncDependencies]] 0
[[EvaluationError]] C 的求值错误

然后,B 在没有错误的情况下完成执行。发生这种情况时,再次调用 AsyncModuleExecutionFulfilled,并将 B.[[Status]] 设置为 evaluated。对 B 调用 GatherAvailableAncestors。不过,A.[[CycleRoot]] 是 A,而 A 存在求值错误,因此它不会被加入返回的 sortedExecList,AsyncModuleExecutionFulfilled 会在不进一步处理的情况下返回。以后任何导入 B 的模块,都会根据循环根 A 上由 C 设置的求值错误,从 B.[[CycleRoot]].[[EvaluationError]] 得到拒绝。更新后的模块字段如 表 52 所示。

表 52: 存在错误的模块图中模块 B 完成执行后的模块字段
字段
模块
A B
[[DFSAncestorIndex]] 0 0
[[Status]] evaluated evaluated
[[AsyncEvaluationOrder]] 4 1
[[AsyncParentModules]] « » « A »
[[PendingAsyncDependencies]] 0 0
[[EvaluationError]] C 的求值错误 empty

16.2.1.7 Source Text Module Records

Source Text Module Record 用于表示有关模块的信息,该模块由使用目标符号 Module 解析的 ECMAScript 源文本(11)定义。其字段包含有关模块所导入和导出名称的归纳信息,其具体方法使用这些归纳信息来链接和求值模块。

Source Text Module Record 可以与抽象 Module Record 类型的其他子类共同存在于一个模块图中,并且可以与 Cyclic Module Record 类型的其他子类参与循环。

除 表 41 中定义的字段外,Source Text Module Record 还具有 表 53 中列出的附加字段。每个字段最初都在 ParseModule 中设置。

表 53: Source Text Module Records 的附加字段
字段名称 值类型 含义
[[ECMAScriptCode]] a Parse Node 使用 Module 作为目标符号解析此模块源文本的结果。
[[Context]] an ECMAScript code execution context or empty 与此模块关联的执行上下文。在模块环境初始化之前,它为 empty。
[[ImportMeta]] an Object or empty 通过 import.meta 元属性暴露的对象。在 ECMAScript 代码访问它之前,它为 empty。
[[ImportEntries]] a List of ImportEntry Records 从此模块代码派生的 ImportEntry record 的 List。
[[LocalExportEntries]] a List of ExportEntry Records 从此模块代码派生的 ExportEntry record 的 List,这些 record 对应于模块内部出现的声明。
[[IndirectExportEntries]] a List of ExportEntry Records 从此模块代码派生的 ExportEntry record 的 List,这些 record 对应于模块内部出现的重新导出的导入,或者来自 export * as namespace 声明的导出。
[[StarExportEntries]] a List of ExportEntry Records 从此模块代码派生的 ExportEntry record 的 List,这些 record 对应于模块内部出现的 export * 声明,但不包括 export * as namespace 声明。

ImportEntry Record 是归纳单个声明式导入相关信息的 Record。每个 ImportEntry Record 都具有 表 54 中定义的字段:

表 54: ImportEntry Record 字段
字段名称 值类型 含义
[[ModuleRequest]] a ModuleRequest Record 表示 ImportDeclaration 的 ModuleSpecifier 和导入属性的 ModuleRequest Record。
[[ImportName]] a String or namespace 由 [[ModuleRequest]] 标识的模块导出所需绑定时使用的名称。值 namespace 表示导入请求针对目标模块的命名空间对象。
[[LocalName]] a String 在导入模块内部用于局部访问所导入值的名称。
注 1

表 55 给出了用于表示句法导入形式的 ImportEntry record 字段示例:

表 55 (资料性): 导入形式到 ImportEntry Records 的映射
导入语句形式 [[ModuleRequest]] [[ImportName]] [[LocalName]]
import v from "mod"; "mod" "default" "v"
import * as ns from "mod"; "mod" namespace "ns"
import {x} from "mod"; "mod" "x" "x"
import {x as v} from "mod"; "mod" "x" "v"
import "mod"; 不创建 ImportEntry Record。

ExportEntry Record 是归纳单个声明式导出相关信息的 Record。每个 ExportEntry Record 都具有 表 56 中定义的字段:

表 56: ExportEntry Record 字段
字段名称 值类型 含义
[[ExportName]] a String or null 此模块用于导出该绑定的名称。
[[ModuleRequest]] a ModuleRequest Record or null 表示 ExportDeclaration 的 ModuleSpecifier 和导入属性的 ModuleRequest Record。如果 ExportDeclaration 没有 ModuleSpecifier,则为 null。
[[ImportName]] a String, null, namespace, or all-but-default 由 [[ModuleRequest]] 标识的模块导出所需绑定时使用的名称。如果 ExportDeclaration 没有 ModuleSpecifier,则为 null。namespace 用于 export * as ns from "mod" 声明。all-but-default 用于 export * from "mod" 声明。
[[LocalName]] a String or null 在导入模块内部用于局部访问所导出值的名称。如果无法从模块内部局部访问导出的值,则为 null。
注 2

表 57 给出了用于表示句法导出形式的 ExportEntry record 字段示例:

表 57 (资料性): 导出形式到 ExportEntry Records 的映射
导出语句形式 [[ExportName]] [[ModuleRequest]] [[ImportName]] [[LocalName]]
export var v; "v" null null "v"
export default function f() {} "default" null null "f"
export default function () {} "default" null null "*default*"
export default 42; "default" null null "*default*"
export {x}; "x" null null "x"
export {v as x}; "x" null null "v"
export {x} from "mod"; "x" "mod" "x" null
export {v as x} from "mod"; "x" "mod" "v" null
export * from "mod"; null "mod" all-but-default null
export * as ns from "mod"; "ns" "mod" namespace null

以下定义规定 Source Text Module Record 所需的具体方法和其他抽象操作

16.2.1.7.1 ParseModule ( sourceText, realm, hostDefined )

抽象操作 ParseModule,接收参数 sourceText ((String 或 a sequence of Unicode code points))、realm (Realm 记录) 和 hostDefined (任意值);返回值:(Source Text Module 记录 或 a non-empty List of SyntaxError objects)。 它根据将 sourceText 作为 Module 解析的结果创建 Source Text Module Record。 调用时执行以下步骤:

  1. 令 body 为 ParseText(sourceText, Module)。
  2. 如果 body 是错误的 List,则返回 body。
  3. 令 requestedModules 为 body 的 ModuleRequests。
  4. 令 importEntries 为 body 的 ImportEntries。
  5. 令 importedBoundNames 为 ImportedLocalNames(importEntries)。
  6. 令 indirectExportEntries 为新的空 List。
  7. 令 localExportEntries 为新的空 List。
  8. 令 starExportEntries 为新的空 List。
  9. 令 exportEntries 为 body 的 ExportEntries。
  10. 对 exportEntries 的每个 ExportEntry Record exportEntry,执行
    1. 如果 exportEntry.[[ModuleRequest]] 是 null,则
      1. 如果 importedBoundNames 不包含 exportEntry.[[LocalName]],则
        1. 将 exportEntry 追加到 localExportEntries。
      2. 否则,
        1. 注:当导出最初从另一个模块导入的绑定或命名空间对象时,会重写 ExportEntry Record,使其形式与直接从原始模块重新导出该绑定或命名空间对象时的形式相同,而不是先导入再导出。这样,通过 export * from 以同一名称两次导出同一绑定或命名空间所产生的冲突就可以被忽略,而不是在 Source Text Module Records 的 ResolveExport 具体方法的步骤 9.e.iii 中被视为歧义。
        2. 令 importEntry 为 importEntries 中 [[LocalName]] 是 exportEntry.[[LocalName]] 的元素。
        3. 将 ExportEntry Record { [[ModuleRequest]]: importEntry.[[ModuleRequest]], [[ImportName]]: importEntry.[[ImportName]], [[LocalName]]: null, [[ExportName]]: exportEntry.[[ExportName]] } 追加到 indirectExportEntries。
    2. 否则如果 exportEntry.[[ImportName]] 是 all-but-default,则
      1. 断言:exportEntry.[[ExportName]] 是 null。
      2. 将 exportEntry 追加到 starExportEntries。
    3. 否则,
      1. 将 exportEntry 追加到 indirectExportEntries。
  11. 令 async 为 body Contains await。
  12. 返回 Source Text Module Record { [[Realm]]: realm, [[Environment]]: empty, [[Namespace]]: empty, [[CycleRoot]]: empty, [[HasTLA]]: async, [[AsyncEvaluationOrder]]: unset, [[TopLevelCapability]]: empty, [[AsyncParentModules]]: « », [[PendingAsyncDependencies]]: empty, [[Status]]: new, [[EvaluationError]]: empty, [[HostDefined]]: hostDefined, [[ECMAScriptCode]]: body, [[Context]]: empty, [[ImportMeta]]: empty, [[RequestedModules]]: requestedModules, [[LoadedModules]]: « », [[ImportEntries]]: importEntries, [[LocalExportEntries]]: localExportEntries, [[IndirectExportEntries]]: indirectExportEntries, [[StarExportEntries]]: starExportEntries, [[DFSAncestorIndex]]: empty }。
注

实现可以在对该模块源文本执行 ParseModule 之前解析模块源文本,并分析其中的提前错误条件。不过,任何错误的报告都必须推迟到本规范实际对该源文本执行 ParseModule 时。

16.2.1.7.2 Module Record 抽象方法的实现

以下是 Source Text Module Record 的具体方法,它们实现 表 40 中定义的相应 Module Record 抽象方法。

16.2.1.7.2.1 GetExportedNames ( [ exportStarSet ] )

a Source Text Module Record module的具体方法 GetExportedNames,接收可选参数 exportStarSet (列表 (元素:Source Text Module 记录));返回值:列表 (元素:String)。 调用时执行以下步骤:

  1. 断言:module.[[Status]] 不是 new。
  2. 如果不存在 exportStarSet,则将 exportStarSet 设置为新的空 List。
  3. 如果 exportStarSet 包含 module,则
    1. 断言:我们已到达 export * 循环的起点。
    2. 返回新的空 List。
  4. 将 module 追加到 exportStarSet。
  5. 令 exportedNames 为新的空 List。
  6. 对 module.[[LocalExportEntries]] 的每个 ExportEntry Record exportEntry,执行
    1. 断言:module 为此导出提供直接绑定。
    2. 断言:exportEntry.[[ExportName]] 不是 null。
    3. 将 exportEntry.[[ExportName]] 追加到 exportedNames。
  7. 对 module.[[IndirectExportEntries]] 的每个 ExportEntry Record exportEntry,执行
    1. 断言:module 为此导出导入特定绑定。
    2. 断言:exportEntry.[[ExportName]] 不是 null。
    3. 将 exportEntry.[[ExportName]] 追加到 exportedNames。
  8. 对 module.[[StarExportEntries]] 的每个 ExportEntry Record exportEntry,执行
    1. 断言:exportEntry.[[ModuleRequest]] 不是 null。
    2. 令 requestedModule 为 GetImportedModule(module, exportEntry.[[ModuleRequest]])。
    3. 令 starNames 为 requestedModule.GetExportedNames(exportStarSet)。
    4. 对 starNames 的每个元素 name,执行
      1. 如果 name 不是 "default",则
        1. 如果 exportedNames 不包含 name,则
          1. 将 name 追加到 exportedNames。
  9. 返回 exportedNames。
注

GetExportedNames 不会过滤具有歧义星号导出绑定的名称,也不会为其抛出异常。

16.2.1.7.2.2 ResolveExport ( exportName [ , resolveSet ] )

a Source Text Module Record module的具体方法 ResolveExport,接收参数 exportName (String)和可选参数 resolveSet (列表 (元素:记录 (字段:[[Module]] (Module 记录), [[ExportName]] (String))));返回值:(ResolvedBinding 记录、null 或 ambiguous)。

ResolveExport 尝试将导入绑定解析到实际定义它的模块和局部绑定名称。定义模块可以是调用此方法的 Module Record 所表示的模块,也可以是该模块导入的其他模块。参数 resolveSet 用于检测无法解析的循环导入/导出路径。如果到达由特定 Module Record 和 exportName 组成、且已经存在于 resolveSet 中的二元组,则说明遇到了导入循环。在递归调用 ResolveExport 之前,会将由 module 和 exportName 组成的二元组添加到 resolveSet。

如果找到定义模块,则返回 ResolvedBinding Record { [[Module]], [[BindingName]] }。除非这是没有局部绑定的命名空间导出,否则此 record 标识最初请求的导出的已解析绑定。在这种情况下,[[BindingName]] 将设置为 namespace。如果没有找到定义或发现请求是循环的,则返回 null。如果发现请求存在歧义,则返回 ambiguous。

调用时执行以下步骤:

  1. 断言:module.[[Status]] 不是 new。
  2. 如果不存在 resolveSet,则将 resolveSet 设置为新的空 List。
  3. 对 resolveSet 的每个 Record { [[Module]], [[ExportName]] } record,执行
    1. 如果 module 和 record.[[Module]] 是同一个 Module Record,并且 exportName 是 record.[[ExportName]],则
      1. 断言:这是循环导入请求。
      2. 返回 null。
  4. 将 Record { [[Module]]: module, [[ExportName]]: exportName } 追加到 resolveSet。
  5. 对 module.[[LocalExportEntries]] 的每个 ExportEntry Record exportEntry,执行
    1. 如果 exportEntry.[[ExportName]] 是 exportName,则
      1. 断言:module 为此导出提供直接绑定。
      2. 返回 ResolvedBinding Record { [[Module]]: module, [[BindingName]]: exportEntry.[[LocalName]] }。
  6. 对 module.[[IndirectExportEntries]] 的每个 ExportEntry Record exportEntry,执行
    1. 如果 exportEntry.[[ExportName]] 是 exportName,则
      1. 断言:exportEntry.[[ModuleRequest]] 不是 null。
      2. 令 importedModule 为 GetImportedModule(module, exportEntry.[[ModuleRequest]])。
      3. 如果 exportEntry.[[ImportName]] 是 namespace,则
        1. 断言:module 不为此导出提供直接绑定。
        2. 返回 ResolvedBinding Record { [[Module]]: importedModule, [[BindingName]]: namespace }。
      4. 断言:module 为此导出导入特定绑定。
      5. 断言:exportEntry.[[ImportName]] 是 String。
      6. 返回 importedModule.ResolveExport(exportEntry.[[ImportName]], resolveSet)。
  7. 如果 exportName 是 "default",则
    1. 断言:此模块未显式定义 default 导出。
    2. 返回 null。
    3. 注:default 导出无法由 export * from "mod" 声明提供。
  8. 令 starResolution 为 null。
  9. 对 module.[[StarExportEntries]] 的每个 ExportEntry Record exportEntry,执行
    1. 断言:exportEntry.[[ModuleRequest]] 不是 null。
    2. 令 importedModule 为 GetImportedModule(module, exportEntry.[[ModuleRequest]])。
    3. 令 resolution 为 importedModule.ResolveExport(exportName, resolveSet)。
    4. 如果 resolution 是 ambiguous,则返回 ambiguous。
    5. 如果 resolution 不是 null,则
      1. 断言:resolution 是 ResolvedBinding Record。
      2. 如果 starResolution 是 null,则
        1. 将 starResolution 设置为 resolution。
      3. 否则,
        1. 断言:有不止一个 * 导出包含请求的名称。
        2. 如果 resolution.[[Module]] 和 starResolution.[[Module]] 不是同一个 Module Record,则返回 ambiguous。
        3. 如果 resolution.[[BindingName]] 不是 starResolution.[[BindingName]],则返回 ambiguous。
  10. 返回 starResolution。

16.2.1.7.3 Cyclic Module Record 抽象方法的实现

以下是 Source Text Module Record 的具体方法,它们实现 表 42 中定义的相应 Cyclic Module Record 抽象方法。

16.2.1.7.3.1 InitializeEnvironment ( )

a Source Text Module Record module的具体方法 InitializeEnvironment,接收无参数;返回值:(正常完成 (值:unused) 或 抛出完成)。 调用时执行以下步骤:

  1. 对 module.[[IndirectExportEntries]] 的每个 ExportEntry Record exportEntry,执行
    1. 断言:exportEntry.[[ExportName]] 不是 null。
    2. 令 resolution 为 module.ResolveExport(exportEntry.[[ExportName]])。
    3. 如果 resolution 是 null 或 ambiguous,则抛出 SyntaxError 异常。
    4. 断言:resolution 是 ResolvedBinding Record。
  2. 断言:来自 module 的所有具名导出都可解析。
  3. 令 realm 为 module.[[Realm]]。
  4. 断言:realm 不是 undefined。
  5. 令 envRecord 为 NewModuleEnvironment(realm.[[GlobalEnv]])。
  6. 将 module.[[Environment]] 设置为 envRecord。
  7. 对 module.[[ImportEntries]] 的每个 ImportEntry Record importEntry,执行
    1. 令 importedModule 为 GetImportedModule(module, importEntry.[[ModuleRequest]])。
    2. 如果 importEntry.[[ImportName]] 是 namespace,则
      1. 令 namespace 为 GetModuleNamespace(importedModule)。
      2. 执行 ! envRecord.CreateImmutableBinding(importEntry.[[LocalName]], true)。
      3. 执行 ! envRecord.InitializeBinding(importEntry.[[LocalName]], namespace)。
    3. 否则,
      1. 断言:importEntry.[[ImportName]] 是 String。
      2. 令 resolution 为 importedModule.ResolveExport(importEntry.[[ImportName]])。
      3. 如果 resolution 是 null 或 ambiguous,则抛出 SyntaxError 异常。
      4. 如果 resolution.[[BindingName]] 是 namespace,则
        1. 令 namespace 为 GetModuleNamespace(resolution.[[Module]])。
        2. 执行 ! envRecord.CreateImmutableBinding(importEntry.[[LocalName]], true)。
        3. 执行 ! envRecord.InitializeBinding(importEntry.[[LocalName]], namespace)。
      5. 否则,
        1. 执行 CreateImportBinding(envRecord, importEntry.[[LocalName]], resolution.[[Module]], resolution.[[BindingName]])。
  8. 令 moduleContext 为新的 ECMAScript 代码执行上下文。
  9. 将 moduleContext 的 Function 设置为 null。
  10. 断言:module.[[Realm]] 不是 undefined。
  11. 将 moduleContext 的 Realm 设置为 module.[[Realm]]。
  12. 将 moduleContext 的 ScriptOrModule 设置为 module。
  13. 将 moduleContext 的 VariableEnvironment 设置为 module.[[Environment]]。
  14. 将 moduleContext 的 LexicalEnvironment 设置为 module.[[Environment]]。
  15. 将 moduleContext 的 PrivateEnvironment 设置为 null。
  16. 将 module.[[Context]] 设置为 moduleContext。
  17. 将 moduleContext 压入执行上下文栈;moduleContext 现在成为正在运行的执行上下文。
  18. 令 code 为 module.[[ECMAScriptCode]]。
  19. 令 variableDecls 为 code 的 VarScopedDeclarations。
  20. 令 declaredVariableNames 为新的空 List。
  21. 对 variableDecls 的每个元素 variableDecl,执行
    1. 对 variableDecl 的 BoundNames 的每个元素 name,执行
      1. 如果 declaredVariableNames 不包含 name,则
        1. 执行 ! envRecord.CreateMutableBinding(name, false)。
        2. 执行 ! envRecord.InitializeBinding(name, undefined)。
        3. 将 name 追加到 declaredVariableNames。
  22. 令 lexicalDecls 为 code 的 LexicallyScopedDeclarations。
  23. 令 privateEnv 为 null。
  24. 对 lexicalDecls 的每个元素 lexicalDecl,执行
    1. 对 lexicalDecl 的 BoundNames 的每个元素 name,执行
      1. 如果 lexicalDecl 的 IsConstantDeclaration 是 true,则
        1. 执行 ! envRecord.CreateImmutableBinding(name, true)。
      2. 否则,
        1. 执行 ! envRecord.CreateMutableBinding(name, false)。
      3. 如果 lexicalDecl 是 FunctionDeclaration、GeneratorDeclaration、AsyncFunctionDeclaration 或 AsyncGeneratorDeclaration 之一,则
        1. 令 funcObj 为以 envRecord 和 privateEnv 为参数对 lexicalDecl 执行 InstantiateFunctionObject 的结果。
        2. 执行 ! envRecord.InitializeBinding(name, funcObj)。
  25. 从执行上下文栈中移除 moduleContext。
  26. 返回 unused。

16.2.1.7.3.2 ExecuteModule ( [ capability ] )

a Source Text Module Record module的具体方法 ExecuteModule,接收可选参数 capability (PromiseCapability 记录);返回值:(正常完成 (值:unused) 或 抛出完成)。 调用时执行以下步骤:

  1. 断言:module 已被链接,并且其模块环境中的声明已被实例化。
  2. 令 moduleContext 为 module.[[Context]]。
  3. 如果 module.[[HasTLA]] 是 false,则
    1. 断言:不存在 capability。
    2. 令 env 为 module.[[Environment]]。
    3. 挂起正在运行的执行上下文。
    4. 将 moduleContext 压入执行上下文栈;moduleContext 现在成为正在运行的执行上下文。
    5. 令 result 为 Completion(module.[[ECMAScriptCode]] 的 Evaluation)。
    6. 将 result 设置为 Completion(DisposeResources(env.[[DisposableResourceStack]], result))。
    7. 挂起 moduleContext 并将其从执行上下文栈中移除。
    8. 恢复当前位于执行上下文栈顶部的上下文,并将其作为正在运行的执行上下文。
    9. 如果 result 是突然完成,则
      1. 返回 ? result。
  4. 否则,
    1. 断言:capability 是 PromiseCapability Record。
    2. 执行 AsyncBlockStart(capability, module.[[ECMAScriptCode]], moduleContext)。
  5. 返回 unused。

16.2.1.8 Synthetic Module Records

Synthetic Module Record 用于表示由规范定义的模块相关信息。其导出名称在创建时静态定义,而对应值可以随时间通过 SetSyntheticModuleExport 更改。它没有导入或依赖项。

注
Synthetic Module Record 可用于定义各种模块类型:例如 JSON 模块或 CSS 模块。

除 表 39 中定义的字段外,Synthetic Module Record 还具有 表 58 中列出的附加字段。

表 58: Synthetic Module Records 的附加字段
字段名称 值类型 含义
[[ExportNames]] a List of Strings 模块的导出名称。此列表不包含重复项。
[[EvaluationSteps]] an Abstract Closure 对模块求值时要执行的初始化逻辑,以 Synthetic Module Record 作为其唯一参数。它不得修改 [[ExportNames]]。它可以返回突然完成。

16.2.1.8.1 CreateDefaultExportSyntheticModule ( defaultExport )

抽象操作 CreateDefaultExportSyntheticModule,接收参数 defaultExport (ECMAScript 语言值);返回值:Synthetic Module 记录。 它创建一个默认导出为 defaultExport 的 Synthetic Module Record。 调用时执行以下步骤:

  1. 令 realm 为当前 Realm Record。
  2. 令 setDefaultExport 为一个具有参数 (module) 的新 Abstract Closure,它捕获 defaultExport,并在被调用时执行以下步骤:
    1. 执行 SetSyntheticModuleExport(module, "default", defaultExport)。
    2. 返回 NormalCompletion(unused)。
  3. 返回 Synthetic Module Record { [[Realm]]: realm, [[Environment]]: empty, [[Namespace]]: empty, [[HostDefined]]: undefined, [[ExportNames]]: « "default" », [[EvaluationSteps]]: setDefaultExport }。

16.2.1.8.2 ParseJSONModule ( source )

抽象操作 ParseJSONModule,接收参数 source (String);返回值:(正常完成 (值:Synthetic Module 记录) 或 抛出完成)。 调用时执行以下步骤:

  1. 令 parseResult 为 ? ParseJSON(source)。
  2. 返回 CreateDefaultExportSyntheticModule(parseResult.[[Value]])。

16.2.1.8.3 SetSyntheticModuleExport ( module, exportName, exportValue )

抽象操作 SetSyntheticModuleExport,接收参数 module (Synthetic Module 记录)、exportName (String) 和 exportValue (ECMAScript 语言值);返回值:unused。 它可用于设置或更改 Synthetic Module Record 的现有导出的导出值。 调用时执行以下步骤:

  1. 断言:module.[[ExportNames]] 包含 exportName。
  2. 令 envRecord 为 module.[[Environment]]。
  3. 断言:envRecord 不是 empty。
  4. 执行 ! envRecord.SetMutableBinding(exportName, exportValue, true)。
  5. 返回 unused。

16.2.1.8.4 Module Record 抽象方法的实现

以下是 Synthetic Module Record 的具体方法,它们实现 表 40 中定义的相应 Module Record 抽象方法。

16.2.1.8.4.1 LoadRequestedModules ( [ hostDefined ] )

a Synthetic Module Record module的具体方法 LoadRequestedModules,接收可选参数 hostDefined (任意值);返回值:Promise。 调用时执行以下步骤:

  1. 注:此 LoadRequestedModules 实现不使用 hostDefined。
  2. 返回 ! PromiseResolve(%Promise%, undefined)。
注
Synthetic Module Record 没有依赖项。

16.2.1.8.4.2 GetExportedNames ( [ exportStarSet ] )

a Synthetic Module Record module的具体方法 GetExportedNames,接收可选参数 exportStarSet (列表 (元素:Source Text Module 记录));返回值:列表 (元素:String)。 调用时执行以下步骤:

  1. 注:此 GetExportedNames 实现不使用 exportStarSet。
  2. 返回 module.[[ExportNames]]。

16.2.1.8.4.3 ResolveExport ( exportName [ , resolveSet ] )

a Synthetic Module Record module的具体方法 ResolveExport,接收参数 exportName (String)和可选参数 resolveSet (列表 (元素:记录 (字段:[[Module]] (Module 记录), [[ExportName]] (String))));返回值:(ResolvedBinding 记录、null 或 ambiguous)。 调用时执行以下步骤:

  1. 注:此 ResolveExport 实现不使用 resolveSet。
  2. 如果 module.[[ExportNames]] 不包含 exportName,则返回 null。
  3. 返回 ResolvedBinding Record { [[Module]]: module, [[BindingName]]: exportName }。

16.2.1.8.4.4 Link ( )

a Synthetic Module Record module的具体方法 Link,接收无参数;返回值:正常完成 (值:unused)。 调用时执行以下步骤:

  1. 令 realm 为 module.[[Realm]]。
  2. 令 envRecord 为 NewModuleEnvironment(realm.[[GlobalEnv]])。
  3. 将 module.[[Environment]] 设置为 envRecord。
  4. 对 module.[[ExportNames]] 的每个 String exportName,执行
    1. 执行 ! envRecord.CreateMutableBinding(exportName, false)。
    2. 执行 ! envRecord.InitializeBinding(exportName, undefined)。
  5. 返回 NormalCompletion(unused)。

16.2.1.8.4.5 Evaluate ( )

a Synthetic Module Record module的具体方法 Evaluate,接收无参数;返回值:Promise。 调用时执行以下步骤:

  1. 令 moduleContext 为新的 ECMAScript 代码执行上下文。
  2. 将 moduleContext 的 Function 设置为 null。
  3. 将 moduleContext 的 Realm 设置为 module.[[Realm]]。
  4. 将 moduleContext 的 ScriptOrModule 设置为 module。
  5. 将 moduleContext 的 VariableEnvironment 设置为 module.[[Environment]]。
  6. 将 moduleContext 的 LexicalEnvironment 设置为 module.[[Environment]]。
  7. 挂起正在运行的执行上下文。
  8. 将 moduleContext 压入执行上下文栈;moduleContext 现在成为正在运行的执行上下文。
  9. 令 steps 为 module.[[EvaluationSteps]]。
  10. 令 result 为 Completion(steps(module))。
  11. 挂起 moduleContext 并将其从执行上下文栈中移除。
  12. 恢复当前位于执行上下文栈顶部的上下文,并将其作为正在运行的执行上下文。
  13. 令 promiseCapability 为 ! NewPromiseCapability(%Promise%)。
  14. IfAbruptRejectPromise(result, promiseCapability)。
  15. 执行 ! Call(promiseCapability.[[Resolve]], undefined, « undefined »)。
  16. 返回 promiseCapability.[[Promise]]。

16.2.1.9 GetImportedModule ( referrer, request )

抽象操作 GetImportedModule,接收参数 referrer (Cyclic Module 记录) 和 request (ModuleRequest 记录);返回值:Module 记录。 调用时执行以下步骤:

  1. 令 records 为一个 List,它由 referrer.[[LoadedModules]] 的每个 LoadedModuleRequest Record r 组成,其中 ModuleRequestsEqual(r, request) 是 true。
  2. 断言:records 恰好有一个元素,因为在调用此抽象操作之前,LoadRequestedModules 已经在 referrer 上成功完成。
  3. 令 record 为 records 的唯一元素。
  4. 返回 record.[[Module]]。

16.2.1.10 HostLoadImportedModule ( referrer, moduleRequest, hostDefined, payload )

宿主定义的抽象操作 HostLoadImportedModule,接收参数 referrer ((Script 记录、Cyclic Module 记录 或 Realm 记录))、moduleRequest (ModuleRequest 记录)、hostDefined (任意值) 和 payload ((GraphLoadingState 记录 或 PromiseCapability 记录));返回值:unused。

注 1

referrer 可以是 Realm Record 的一个示例出现在 Web 浏览器宿主中。在那里,如果用户点击由以下代码给出的控件

<button type="button" onclick="import('./foo.mjs')">点击我</button>

那么在 import() 表达式运行时将没有活动的 script 或 module。更一般地说,在宿主将 ScriptOrModule 组成部分为 null 的执行上下文压入执行上下文栈的任何情况下,都可能发生这种情况。

HostLoadImportedModule 的实现必须符合以下要求:

实际执行的过程由宿主定义,但通常包括执行加载相应 Module Record 所需的任何 I/O 操作。多个不同的 (referrer, moduleRequest.[[Specifier]], moduleRequest.[[Attributes]]) 三元组可以映射到同一个 Module Record 实例。实际映射语义由宿主定义,但通常在映射过程中会对 specifier 应用规范化过程。典型的规范化过程包括展开相对路径和缩写路径说明符等操作。

注 2

上述文本要求宿主在使用 type: "json" 导入时支持 JSON 模块(并且 HostLoadImportedModule 正常完成),但并不禁止宿主在未使用 type: "json" 导入时支持 JSON 模块。

16.2.1.11 FinishLoadingImportedModule ( referrer, moduleRequest, payload, result )

抽象操作 FinishLoadingImportedModule,接收参数 referrer ((Script 记录、Cyclic Module 记录 或 Realm 记录))、moduleRequest (ModuleRequest 记录)、payload ((GraphLoadingState 记录 或 PromiseCapability 记录)) 和 result ((正常完成 (值:Module 记录) 或 抛出完成));返回值:unused。 调用时执行以下步骤:

  1. 如果 result 是正常完成,则
    1. 如果 referrer.[[LoadedModules]] 包含某个 LoadedModuleRequest Record record,使得 ModuleRequestsEqual(record, moduleRequest) 是 true,则
      1. 断言:record.[[Module]] 和 result.[[Value]] 是同一个 Module Record。
    2. 否则,
      1. 将 LoadedModuleRequest Record { [[Specifier]]: moduleRequest.[[Specifier]], [[Attributes]]: moduleRequest.[[Attributes]], [[Module]]: result.[[Value]] } 追加到 referrer.[[LoadedModules]]。
  2. 如果 payload 是 GraphLoadingState Record,则
    1. 执行 ContinueModuleLoading(payload, result)。
  3. 否则,
    1. 执行 ContinueDynamicImport(payload, result)。
  4. 返回 unused。

16.2.1.12 AllImportAttributesSupported ( attrs )

抽象操作 AllImportAttributesSupported,接收参数 attrs (列表 (元素:ImportAttribute 记录));返回值:Boolean。 调用时执行以下步骤:

  1. 令 supported 为 HostGetSupportedImportAttributes()。
  2. 对 attrs 的每个 ImportAttribute Record attr,执行
    1. 如果 supported 不包含 attr.[[Key]],则返回 false。
  3. 返回 true。

16.2.1.12.1 HostGetSupportedImportAttributes ( )

宿主定义的抽象操作 HostGetSupportedImportAttributes,接收无参数;返回值:列表 (元素:String)。 它允许宿主环境指定其支持哪些导入属性。只有键受支持的属性才会提供给宿主。

HostGetSupportedImportAttributes 的实现必须符合以下要求:

  • 它必须返回 String 的 List,每个 String 表示一个受支持的属性。
  • 每次调用此操作时,都必须返回内容相同、顺序相同的同一个 List。

HostGetSupportedImportAttributes 的默认实现是返回新的空 List。

注
要求宿主指定其支持的导入属性,而不是将所有属性传递给宿主再由宿主选择要处理哪些属性,其目的是确保不同宿主以一致方式处理不受支持的属性。

16.2.1.13 GetModuleNamespace ( module )

抽象操作 GetModuleNamespace,接收参数 module (instance of a concrete subclass of Module 记录);返回值:a Module Namespace Object。 它获取表示 module 导出的 Module Namespace Object,在首次请求时惰性创建该对象,并将其存储在 module.[[Namespace]] 中以供将来获取。 调用时执行以下步骤:

  1. 断言:如果 module 是 Cyclic Module Record,则 module.[[Status]] 不是 new 或 unlinked。
  2. 令 namespace 为 module.[[Namespace]]。
  3. 如果 namespace 是 empty,则
    1. 令 exportedNames 为 module.GetExportedNames()。
    2. 令 unambiguousNames 为新的空 List。
    3. 对 exportedNames 的每个元素 name,执行
      1. 令 resolution 为 module.ResolveExport(name)。
      2. 如果 resolution 是 ResolvedBinding Record,则将 name 追加到 unambiguousNames。
    4. 将 namespace 设置为 ModuleNamespaceCreate(module, unambiguousNames)。
  4. 返回 namespace。
注

GetModuleNamespace 永远不会抛出异常。相反,无法解析的名称此时会直接从命名空间中排除。除非它们全都是未在任何地方被显式请求的歧义星号导出,否则它们之后会导致真正的链接错误。

16.2.1.14 Runtime Semantics: Evaluation

Module : [empty]
  1. 返回 undefined。
ModuleBody : ModuleItemList
  1. 令 result 为 Completion(ModuleItemList 的 Evaluation)。
  2. 如果 result 是正常完成且 result.[[Value]] 是 empty,则
    1. 返回 undefined。
  3. 返回 ? result。
ModuleItemList : ModuleItemList ModuleItem
  1. 令 sl 为 ? ModuleItemList 的 Evaluation。
  2. 令 s 为 Completion(ModuleItem 的 Evaluation)。
  3. 返回 ? UpdateEmpty(s, sl)。
注

ModuleItemList 的值是 ModuleItemList 中最后一个产生值的项的值。

ModuleItem : ImportDeclaration
  1. 返回 empty。

16.2.2 导入

语法

ImportDeclaration : import ImportClause FromClause WithClauseopt ; import ModuleSpecifier WithClauseopt ; ImportClause : ImportedDefaultBinding NameSpaceImport NamedImports ImportedDefaultBinding , NameSpaceImport ImportedDefaultBinding , NamedImports ImportedDefaultBinding : ImportedBinding NameSpaceImport : * as ImportedBinding NamedImports : { } { ImportsList ,opt } FromClause : from ModuleSpecifier ImportsList : ImportSpecifier ImportsList , ImportSpecifier ImportSpecifier : ImportedBinding ModuleExportName as ImportedBinding ModuleSpecifier : StringLiteral ImportedBinding : BindingIdentifier[~Yield, +Await] WithClause : with { } with { WithEntries ,opt } WithEntries : AttributeKey : StringLiteral AttributeKey : StringLiteral , WithEntries AttributeKey : IdentifierName StringLiteral

16.2.2.1 Static Semantics: 提前错误

ModuleItem : ImportDeclaration WithClause : with { WithEntries ,opt }

16.2.2.2 Static Semantics: ImportEntries

语法制导操作 ImportEntries,接收无参数;返回值:列表 (元素:ImportEntry 记录)。 它按以下产生式分别定义:

Module : [empty]
  1. 返回新的空 List。
ModuleItemList : ModuleItemList ModuleItem
  1. 令 entries1 为 ModuleItemList 的 ImportEntries。
  2. 令 entries2 为 ModuleItem 的 ImportEntries。
  3. 返回 entries1 和 entries2 的列表连接。
ModuleItem : ExportDeclaration StatementListItem
  1. 返回新的空 List。
ImportDeclaration : import ImportClause FromClause WithClauseopt ;
  1. 令 module 为 ImportDeclaration 的 ModuleRequests 的唯一元素。
  2. 返回以 module 为参数对 ImportClause 执行 ImportEntriesForModule 的结果。
ImportDeclaration : import ModuleSpecifier WithClauseopt ;
  1. 返回新的空 List。

16.2.2.3 Static Semantics: ImportEntriesForModule

语法制导操作 ImportEntriesForModule,接收参数 module (ModuleRequest 记录);返回值:列表 (元素:ImportEntry 记录)。 它按以下产生式分别定义:

ImportClause : ImportedDefaultBinding , NameSpaceImport
  1. 令 entries1 为以 module 为参数对 ImportedDefaultBinding 执行 ImportEntriesForModule 的结果。
  2. 令 entries2 为以 module 为参数对 NameSpaceImport 执行 ImportEntriesForModule 的结果。
  3. 返回 entries1 和 entries2 的列表连接。
ImportClause : ImportedDefaultBinding , NamedImports
  1. 令 entries1 为以 module 为参数对 ImportedDefaultBinding 执行 ImportEntriesForModule 的结果。
  2. 令 entries2 为以 module 为参数对 NamedImports 执行 ImportEntriesForModule 的结果。
  3. 返回 entries1 和 entries2 的列表连接。
ImportedDefaultBinding : ImportedBinding
  1. 令 localName 为 ImportedBinding 的 BoundNames 的唯一元素。
  2. 令 defaultEntry 为 ImportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: "default", [[LocalName]]: localName }。
  3. 返回 « defaultEntry »。
NameSpaceImport : * as ImportedBinding
  1. 令 localName 为 ImportedBinding 的 StringValue。
  2. 令 entry 为 ImportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: namespace, [[LocalName]]: localName }。
  3. 返回 « entry »。
NamedImports : { }
  1. 返回新的空 List。
ImportsList : ImportsList , ImportSpecifier
  1. 令 specs1 为以 module 为参数对 ImportsList 执行 ImportEntriesForModule 的结果。
  2. 令 specs2 为以 module 为参数对 ImportSpecifier 执行 ImportEntriesForModule 的结果。
  3. 返回 specs1 和 specs2 的列表连接。
ImportSpecifier : ImportedBinding
  1. 令 localName 为 ImportedBinding 的 BoundNames 的唯一元素。
  2. 令 entry 为 ImportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: localName, [[LocalName]]: localName }。
  3. 返回 « entry »。
ImportSpecifier : ModuleExportName as ImportedBinding
  1. 令 importName 为 ModuleExportName 的 StringValue。
  2. 令 localName 为 ImportedBinding 的 StringValue。
  3. 令 entry 为 ImportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: importName, [[LocalName]]: localName }。
  4. 返回 « entry »。

16.2.2.4 Static Semantics: WithClauseToAttributes

语法制导操作 WithClauseToAttributes,接收无参数;返回值:列表 (元素:ImportAttribute 记录)。 它按以下产生式分别定义:

WithClause : with { }
  1. 返回新的空 List。
WithClause : with { WithEntries ,opt }
  1. 令 attrs 为 WithEntries 的 WithClauseToAttributes。
  2. 按 [[Key]] 字段的字典序对 attrs 排序,将每个此类字段的值视为 UTF-16 码元值序列。注:这种排序唯一可观察的方面,是禁止宿主根据属性枚举顺序改变行为。
  3. 返回 attrs。
WithEntries : AttributeKey : StringLiteral
  1. 令 key 为 AttributeKey 的 PropName。
  2. 令 entry 为 ImportAttribute Record { [[Key]]: key, [[Value]]: StringLiteral 的 SV }。
  3. 返回 « entry »。
WithEntries : AttributeKey : StringLiteral , WithEntries
  1. 令 key 为 AttributeKey 的 PropName。
  2. 令 entry 为 ImportAttribute Record { [[Key]]: key, [[Value]]: StringLiteral 的 SV }。
  3. 令 rest 为 WithEntries 的 WithClauseToAttributes。
  4. 返回 « entry » 和 rest 的列表连接。

16.2.3 导出

语法

ExportDeclaration : export ExportFromClause FromClause WithClauseopt ; export NamedExports ; export VariableStatement[~Yield, +Await] export [lookahead ∉ { using, await }] Declaration[~Yield, +Await] export default HoistableDeclaration[~Yield, +Await, +Default] export default ClassDeclaration[~Yield, +Await, +Default] export default [lookahead ∉ { function, async [no LineTerminator here] function, class }] AssignmentExpression[+In, ~Yield, +Await] ; ExportFromClause : * * as ModuleExportName NamedExports NamedExports : { } { ExportsList ,opt } ExportsList : ExportSpecifier ExportsList , ExportSpecifier ExportSpecifier : ModuleExportName ModuleExportName as ModuleExportName

16.2.3.1 Static Semantics: 提前错误

ExportDeclaration : export NamedExports ; 注

上述规则意味着,NamedExports 的每个 ReferencedBindings 都被视为 IdentifierReference。

16.2.3.2 Static Semantics: ExportedBindings

语法制导操作 ExportedBindings,接收无参数;返回值:列表 (元素:String)。

注

ExportedBindings 是与 Module 的 ExportedNames 显式关联的局部绑定名称。

它按以下产生式分别定义:

ModuleItemList : ModuleItemList ModuleItem
  1. 令 names1 为 ModuleItemList 的 ExportedBindings。
  2. 令 names2 为 ModuleItem 的 ExportedBindings。
  3. 返回 names1 和 names2 的列表连接。
ModuleItem : ImportDeclaration StatementListItem
  1. 返回新的空 List。
ExportDeclaration : export ExportFromClause FromClause WithClauseopt ;
  1. 返回新的空 List。
ExportDeclaration : export NamedExports ;
  1. 返回 NamedExports 的 ExportedBindings。
ExportDeclaration : export VariableStatement
  1. 返回 VariableStatement 的 BoundNames。
ExportDeclaration : export Declaration
  1. 返回 Declaration 的 BoundNames。
ExportDeclaration : export default HoistableDeclaration export default ClassDeclaration export default AssignmentExpression ;
  1. 返回此 ExportDeclaration 的 BoundNames。
NamedExports : { }
  1. 返回新的空 List。
ExportsList : ExportsList , ExportSpecifier
  1. 令 names1 为 ExportsList 的 ExportedBindings。
  2. 令 names2 为 ExportSpecifier 的 ExportedBindings。
  3. 返回 names1 和 names2 的列表连接。
ExportSpecifier : ModuleExportName
  1. 返回一个 List,其唯一元素是 ModuleExportName 的 StringValue。
ExportSpecifier : ModuleExportName as ModuleExportName
  1. 返回一个 List,其唯一元素是第一个 ModuleExportName 的 StringValue。

16.2.3.3 Static Semantics: ExportedNames

语法制导操作 ExportedNames,接收无参数;返回值:列表 (元素:String)。

注

ExportedNames 是 Module 显式映射到其某个局部名称绑定的外部可见名称。

它按以下产生式分别定义:

ModuleItemList : ModuleItemList ModuleItem
  1. 令 names1 为 ModuleItemList 的 ExportedNames。
  2. 令 names2 为 ModuleItem 的 ExportedNames。
  3. 返回 names1 和 names2 的列表连接。
ModuleItem : ExportDeclaration
  1. 返回 ExportDeclaration 的 ExportedNames。
ModuleItem : ImportDeclaration StatementListItem
  1. 返回新的空 List。
ExportDeclaration : export ExportFromClause FromClause WithClauseopt ;
  1. 返回 ExportFromClause 的 ExportedNames。
ExportFromClause : *
  1. 返回新的空 List。
ExportFromClause : * as ModuleExportName
  1. 返回一个 List,其唯一元素是 ModuleExportName 的 StringValue。
ExportFromClause : NamedExports
  1. 返回 NamedExports 的 ExportedNames。
ExportDeclaration : export VariableStatement
  1. 返回 VariableStatement 的 BoundNames。
ExportDeclaration : export Declaration
  1. 返回 Declaration 的 BoundNames。
ExportDeclaration : export default HoistableDeclaration export default ClassDeclaration export default AssignmentExpression ;
  1. 返回 « "default" »。
NamedExports : { }
  1. 返回新的空 List。
ExportsList : ExportsList , ExportSpecifier
  1. 令 names1 为 ExportsList 的 ExportedNames。
  2. 令 names2 为 ExportSpecifier 的 ExportedNames。
  3. 返回 names1 和 names2 的列表连接。
ExportSpecifier : ModuleExportName
  1. 返回一个 List,其唯一元素是 ModuleExportName 的 StringValue。
ExportSpecifier : ModuleExportName as ModuleExportName
  1. 返回一个 List,其唯一元素是第二个 ModuleExportName 的 StringValue。

16.2.3.4 Static Semantics: ExportEntries

语法制导操作 ExportEntries,接收无参数;返回值:列表 (元素:ExportEntry 记录)。 它按以下产生式分别定义:

Module : [empty]
  1. 返回新的空 List。
ModuleItemList : ModuleItemList ModuleItem
  1. 令 entries1 为 ModuleItemList 的 ExportEntries。
  2. 令 entries2 为 ModuleItem 的 ExportEntries。
  3. 返回 entries1 和 entries2 的列表连接。
ModuleItem : ImportDeclaration StatementListItem
  1. 返回新的空 List。
ExportDeclaration : export ExportFromClause FromClause WithClauseopt ;
  1. 令 module 为 ExportDeclaration 的 ModuleRequests 的唯一元素。
  2. 返回以 module 为参数对 ExportFromClause 执行 ExportEntriesForModule 的结果。
ExportDeclaration : export NamedExports ;
  1. 返回以 null 为参数对 NamedExports 执行 ExportEntriesForModule 的结果。
ExportDeclaration : export VariableStatement
  1. 令 entries 为新的空 List。
  2. 令 names 为 VariableStatement 的 BoundNames。
  3. 对 names 的每个元素 name,执行
    1. 将 ExportEntry Record { [[ModuleRequest]]: null, [[ImportName]]: null, [[LocalName]]: name, [[ExportName]]: name } 追加到 entries。
  4. 返回 entries。
ExportDeclaration : export Declaration
  1. 令 entries 为新的空 List。
  2. 令 names 为 Declaration 的 BoundNames。
  3. 对 names 的每个元素 name,执行
    1. 将 ExportEntry Record { [[ModuleRequest]]: null, [[ImportName]]: null, [[LocalName]]: name, [[ExportName]]: name } 追加到 entries。
  4. 返回 entries。
ExportDeclaration : export default HoistableDeclaration
  1. 令 names 为 HoistableDeclaration 的 BoundNames。
  2. 令 localName 为 names 的唯一元素。
  3. 返回一个 List,其唯一元素是新的 ExportEntry Record { [[ModuleRequest]]: null, [[ImportName]]: null, [[LocalName]]: localName, [[ExportName]]: "default" }。
ExportDeclaration : export default ClassDeclaration
  1. 令 names 为 ClassDeclaration 的 BoundNames。
  2. 令 localName 为 names 的唯一元素。
  3. 返回一个 List,其唯一元素是新的 ExportEntry Record { [[ModuleRequest]]: null, [[ImportName]]: null, [[LocalName]]: localName, [[ExportName]]: "default" }。
ExportDeclaration : export default AssignmentExpression ;
  1. 令 entry 为 ExportEntry Record { [[ModuleRequest]]: null, [[ImportName]]: null, [[LocalName]]: "*default*", [[ExportName]]: "default" }。
  2. 返回 « entry »。
注

本规范使用 "*default*" 作为匿名默认导出值的合成名称。有关更多详细信息,请参见此注释。

16.2.3.5 Static Semantics: ExportEntriesForModule

语法制导操作 ExportEntriesForModule,接收参数 module ((ModuleRequest 记录 或 null));返回值:列表 (元素:ExportEntry 记录)。 它按以下产生式分别定义:

ExportFromClause : *
  1. 令 entry 为 ExportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: all-but-default, [[LocalName]]: null, [[ExportName]]: null }。
  2. 返回 « entry »。
ExportFromClause : * as ModuleExportName
  1. 令 exportName 为 ModuleExportName 的 StringValue。
  2. 令 entry 为 ExportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: namespace, [[LocalName]]: null, [[ExportName]]: exportName }。
  3. 返回 « entry »。
NamedExports : { }
  1. 返回新的空 List。
ExportsList : ExportsList , ExportSpecifier
  1. 令 specs1 为以 module 为参数对 ExportsList 执行 ExportEntriesForModule 的结果。
  2. 令 specs2 为以 module 为参数对 ExportSpecifier 执行 ExportEntriesForModule 的结果。
  3. 返回 specs1 和 specs2 的列表连接。
ExportSpecifier : ModuleExportName
  1. 令 sourceName 为 ModuleExportName 的 StringValue。
  2. 如果 module 是 null,则
    1. 令 localName 为 sourceName。
    2. 令 importName 为 null。
  3. 否则,
    1. 令 localName 为 null。
    2. 令 importName 为 sourceName。
  4. 返回一个 List,其唯一元素是新的 ExportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: importName, [[LocalName]]: localName, [[ExportName]]: sourceName }。
ExportSpecifier : ModuleExportName as ModuleExportName
  1. 令 sourceName 为第一个 ModuleExportName 的 StringValue。
  2. 令 exportName 为第二个 ModuleExportName 的 StringValue。
  3. 如果 module 是 null,则
    1. 令 localName 为 sourceName。
    2. 令 importName 为 null。
  4. 否则,
    1. 令 localName 为 null。
    2. 令 importName 为 sourceName。
  5. 返回一个 List,其唯一元素是新的 ExportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: importName, [[LocalName]]: localName, [[ExportName]]: exportName }。

16.2.3.6 Static Semantics: ReferencedBindings

语法制导操作 ReferencedBindings,接收无参数;返回值:列表 (元素:解析节点)。 它按以下产生式分别定义:

NamedExports : { }
  1. 返回新的空 List。
ExportsList : ExportsList , ExportSpecifier
  1. 令 names1 为 ExportsList 的 ReferencedBindings。
  2. 令 names2 为 ExportSpecifier 的 ReferencedBindings。
  3. 返回 names1 和 names2 的列表连接。
ExportSpecifier : ModuleExportName as ModuleExportName
  1. 返回第一个 ModuleExportName 的 ReferencedBindings。
ModuleExportName : IdentifierName
  1. 返回一个 List,其唯一元素是 IdentifierName。
ModuleExportName : StringLiteral
  1. 返回一个 List,其唯一元素是 StringLiteral。

16.2.3.7 Runtime Semantics: Evaluation

ExportDeclaration : export ExportFromClause FromClause WithClauseopt ; export NamedExports ;
  1. 返回 empty。
ExportDeclaration : export VariableStatement
  1. 返回 ? VariableStatement 的 Evaluation。
ExportDeclaration : export Declaration
  1. 返回 ? Declaration 的 Evaluation。
ExportDeclaration : export default HoistableDeclaration
  1. 返回 ? HoistableDeclaration 的 Evaluation。
ExportDeclaration : export default ClassDeclaration
  1. 令 value 为 ? ClassDeclaration 的 BindingClassDeclarationEvaluation。
  2. 令 className 为 ClassDeclaration 的 BoundNames 的唯一元素。
  3. 如果 className 是 "*default*",则
    1. 令 envRecord 为正在运行的执行上下文的 LexicalEnvironment。
    2. 执行 ? InitializeBoundName("*default*", value, envRecord)。
  4. 返回 empty。
ExportDeclaration : export default AssignmentExpression ;
  1. 如果 IsAnonymousFunctionDefinition(AssignmentExpression) 是 true,则
    1. 令 value 为 ? 以 "default" 为参数对 AssignmentExpression 执行 NamedEvaluation 的结果。
  2. 否则,
    1. 令 rhs 为 ? AssignmentExpression 的 Evaluation。
    2. 令 value 为 ? GetValue(rhs)。
  3. 令 envRecord 为正在运行的执行上下文的 LexicalEnvironment。
  4. 执行 ? InitializeBoundName("*default*", value, envRecord)。
  5. 返回 empty。