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

The syntax-directed operation ScriptIsStrict takes no arguments and returns a Boolean. It is defined piecewise over the following productions:

Script : ScriptBodyopt
  1. 如果存在 ScriptBodyScriptBodyDirective Prologue 包含 Use Strict Directive,则返回 true
  2. 返回 false

16.1.3 Runtime Semantics: Evaluation

Script : [empty]
  1. 返回 undefined

16.1.4 Script Record

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

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

16.1.5 ParseScript ( sourceText, realm, hostDefined )

The abstract operation ParseScript takes arguments sourceText (a String or a sequence of Unicode code points), realm (a Realm Record), and hostDefined (anything) and returns a Script Record or a non-empty List of SyntaxError objects. 它基于把 sourceText 解析为 Script 的结果创建一个 Script Record。 It performs the following steps when called:

  1. scriptParseText(sourceText, Script)。
  2. 如果 script 是错误列表,则返回 script
  3. 返回 Script Record { [[Realm]]: realm, [[ECMAScriptCode]]: script, [[LoadedModules]]: « », [[HostDefined]]: hostDefined }。
Note

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

16.1.6 ScriptEvaluation ( scriptRecord )

The abstract operation ScriptEvaluation takes argument scriptRecord (a Script Record) and returns either a normal completion containing an ECMAScript language value or an abrupt completion. It performs the following steps when called:

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

16.1.7 GlobalDeclarationInstantiation ( script, envRecord )

The abstract operation GlobalDeclarationInstantiation takes arguments script (a Script Parse Node) and envRecord (a Global Environment Record) and returns either a normal completion containing unused or a throw completion. script 是正在为其建立执行上下文的 ScriptenvRecord 是要在其中创建绑定的全局环境。

Note 1

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

它在被调用时执行以下步骤:

  1. lexicalNamesscriptLexicallyDeclaredNames
  2. variableNamesscriptVarDeclaredNames
  3. lexicalNames 的每个元素 name,执行:
    1. 如果 HasLexicalDeclaration(envRecord, name) 为 true,则抛出一个 SyntaxError 异常。
    2. hasRestrictedGlobal 为 ? HasRestrictedGlobalProperty(envRecord, name)。
    3. 注:全局 varfunction 绑定(由非严格直接 eval 引入的那些绑定除外)是不可配置的,因此是受限制的全局属性。
    4. 如果 hasRestrictedGlobaltrue,则抛出一个 SyntaxError 异常。
  4. variableNames 的每个元素 name,执行:
    1. 如果 HasLexicalDeclaration(envRecord, name) 为 true,则抛出一个 SyntaxError 异常。
  5. variableDeclsscriptVarScopedDeclarations
  6. funcsToInitialize 为一个新的空 List
  7. declaredFuncNames 为一个新的空 List
  8. variableDecls 的每个元素 variableDecl,按 List 的逆序执行:
    1. 如果 variableDecl 不是 VariableDeclarationForBindingBindingIdentifier 中的任一者,则
      1. 断言:variableDeclFunctionDeclarationGeneratorDeclarationAsyncFunctionDeclarationAsyncGeneratorDeclaration
      2. 注:如果同一名称有多个函数声明,则使用最后一个声明。
      3. funcNamevariableDeclBoundNames 的唯一元素。
      4. 如果 declaredFuncNames包含 funcName,则
        1. funcDefinable 为 ? CanDeclareGlobalFunction(envRecord, funcName)。
        2. 如果 funcDefinablefalse,则抛出一个 TypeError 异常。
        3. funcName 追加到 declaredFuncNames
        4. variableDecl 作为 funcsToInitialize 的第一个元素插入。
  9. declaredVariableNames 为一个新的空 List
  10. variableDecls 的每个元素 variableDecl,执行:
    1. 如果 variableDeclVariableDeclarationForBindingBindingIdentifier 中的任一者,则
      1. variableDeclBoundNames 的每个 String name,执行:
        1. 如果 declaredFuncNames包含 name,则
          1. variableDefinable 为 ? CanDeclareGlobalVar(envRecord, name)。
          2. 如果 variableDefinablefalse,则抛出一个 TypeError 异常。
          3. 如果 declaredVariableNames包含 name,则
            1. name 追加到 declaredVariableNames
  11. 注:如果全局对象普通对象,则在此算法步骤之后不会发生异常终止。但是,如果全局对象Proxy 异质对象,它可能表现出会导致以下某些步骤中发生异常终止的行为。
  12. 如果宿主是 Web 浏览器,或以其他方式支持 块级函数声明的 Web 遗留兼容性语义,则
    1. strictscriptScriptIsStrict
    2. 如果 strictfalse,则
      1. declaredFuncOrVariableNamesdeclaredFuncNamesdeclaredVariableNames列表连接
      2. 对每个 FunctionDeclaration funcDecl,其直接包含在任何 BlockCaseClauseDefaultClause xStatementList 中,且 script Contains xtrue,执行:
        1. funcNamefuncDeclBindingIdentifierStringValue
        2. 如果将 FunctionDeclaration funcDecl 替换为以 funcName 作为 BindingIdentifierVariableStatement 不会为 script 产生任何早期错误,则
          1. 如果 HasLexicalDeclaration(envRecord, funcName) 为 false,则
            1. funcDefinable 为 ? CanDeclareGlobalVar(envRecord, funcName)。
            2. 如果 funcDefinabletrue,则
              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. lexicalDeclsscriptLexicallyScopedDeclarations
  14. privateEnvnull
  15. lexicalDecls 的每个元素 lexicalDecl,执行:
    1. 注:词法声明的名称仅在此处实例化,但不初始化。
    2. lexicalDeclBoundNames 的每个元素 name,执行:
      1. 如果 lexicalDeclIsConstantDeclarationtrue,则
        1. 执行 ? envRecord.CreateImmutableBinding(name, true)
      2. 否则,
        1. 执行 ? envRecord.CreateMutableBinding(name, false)
  16. funcsToInitialize 的每个 Parse Node funcDecl,执行:
    1. funcNamefuncDeclBoundNames 的唯一元素。
    2. funcObj 为使用参数 envRecordprivateEnvfuncDecl 执行 InstantiateFunctionObject 的结果。
    3. 执行 ? CreateGlobalFunctionBinding(envRecord, funcName, funcObj, false)。
  17. declaredVariableNames 的每个 String variableName,执行:
    1. 执行 ? CreateGlobalVarBinding(envRecord, variableName, false)。
  18. 返回 unused
Note 2

16.1.1 中指定的早期错误会防止单个 Script包含的声明在 function/var 声明与 let/const/class 声明之间发生名称冲突,以及防止重新声明 let/const/class 绑定。不过,跨越多个 Script 的此类冲突和重新声明会在 GlobalDeclarationInstantiation 期间作为运行时错误被检测到。如果检测到任何此类错误,则不会为该脚本实例化任何绑定。不过,如果全局对象是使用 Proxy 异质对象定义的,则用于检测冲突声明的运行时测试可能不可靠,从而导致 abrupt completion,并且某些全局声明未被实例化。如果发生这种情况,则不会求值该 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 Note

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

ModuleExportName : StringLiteral

16.2.1.2 Static Semantics: ImportedLocalNames ( importEntries )

The abstract operation ImportedLocalNames takes argument importEntries (a List of ImportEntry Records) and returns a List of Strings. 它创建由 importEntries 定义的所有本地名称绑定的 List。 It performs the following steps when called:

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

16.2.1.3 ModuleRequest Record

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

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

LoadedModuleRequest Record 表示导入模块的请求以及所得的 Module Record。它由表 Table 36 中定义的相同字段组成,并额外带有 [[Module]]

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

ImportAttribute Record 由以下字段组成:

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

16.2.1.3.1 ModuleRequestsEqual ( x, y )

The abstract operation ModuleRequestsEqual takes arguments x (a ModuleRequest Record or a LoadedModuleRequest Record) and y (a ModuleRequest Record or a LoadedModuleRequest Record) and returns a Boolean. It performs the following steps when called:

  1. 如果 x.[[Specifier]] 不是 y.[[Specifier]],则返回 false
  2. xAttrsx.[[Attributes]]
  3. yAttrsy.[[Attributes]]
  4. xAttrsCountxAttrs 中元素的数量。
  5. yAttrsCountyAttrs 中元素的数量。
  6. 如果 xAttrsCountyAttrsCount,则返回 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

The syntax-directed operation ModuleRequests takes no arguments and returns a List of ModuleRequest Records. It is defined piecewise over the following productions:

Module : [empty]
  1. 返回新的空 List
ModuleItemList : ModuleItem
  1. 返回 ModuleItemModuleRequests
ModuleItemList : ModuleItemList ModuleItem
  1. requestsModuleItemListModuleRequests
  2. additionalRequestsModuleItemModuleRequests
  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. specifierFromClauseSV
  2. 返回一个 List,其唯一元素为 ModuleRequest Record { [[Specifier]]: specifier, [[Attributes]]: « » }。
ImportDeclaration : import ImportClause FromClause WithClause ;
  1. specifierFromClauseSV
  2. attrsWithClauseWithClauseToAttributes
  3. 返回一个 List,其唯一元素为 ModuleRequest Record { [[Specifier]]: specifier, [[Attributes]]: attrs }。
ImportDeclaration : import ModuleSpecifier ;
  1. specifierModuleSpecifierSV
  2. 返回一个 List,其唯一元素为 ModuleRequest Record { [[Specifier]]: specifier, [[Attributes]]: « » }。
ImportDeclaration : import ModuleSpecifier WithClause ;
  1. specifierModuleSpecifierSV
  2. attrsWithClauseWithClauseToAttributes
  3. 返回一个 List,其唯一元素为 ModuleRequest Record { [[Specifier]]: specifier, [[Attributes]]: attrs }。
ExportDeclaration : export ExportFromClause FromClause ;
  1. specifierFromClauseSV
  2. 返回一个 List,其唯一元素为 ModuleRequest Record { [[Specifier]]: specifier, [[Attributes]]: « » }。
ExportDeclaration : export ExportFromClause FromClause WithClause ;
  1. specifierFromClauseSV
  2. attrsWithClauseWithClauseToAttributes
  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 Record

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

出于规范目的,Module Record 值是 Record 规范类型的值,可以被认为存在于一个简单的面向对象层级中,其中 Module Record 是一个抽象类,具有抽象子类和具体子类。本规范定义名为 Cyclic Module Record 的抽象子类,以及名为 Source Text Module Record 的具体子类。其他规范和实现可以定义附加的 Module Record 子类,对应于它们所定义的替代模块定义设施。

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

Table 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(默认值为 undefined 为需要把附加信息与模块关联起来的宿主环境保留的字段。
Table 40: Abstract Methods of Module Records
方法 目的 定义
LoadRequestedModules ( [ hostDefined ] )

The abstract method LoadRequestedModules takes optional argument hostDefined (anything) and returns a Promise.

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

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

The abstract method GetExportedNames takes optional argument exportStarSet (a List of Source Text Module Records) and returns a List of Strings.

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

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

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

The abstract method ResolveExport takes argument exportName (a String) and optional argument resolveSet (a List of Records with fields [[Module]] (a Module Record) and [[ExportName]] (a String)) and returns a ResolvedBinding Record, null, or ambiguous.

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

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

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

在本规范内,它在以下类型中有定义;宿主可以提供带有自身定义的附加类型:
Evaluate ( )

The abstract method Evaluate takes no arguments and returns a Promise.

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

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

在本规范内,它在以下类型中有定义;宿主可以提供带有自身定义的附加类型:

16.2.1.5.1 EvaluateModuleSync ( module )

The abstract operation EvaluateModuleSync takes argument module (a Module Record) and returns either a normal completion containing unused or a throw completion. 它同步求值 module,前提是调用者保证 module 的求值会返回一个已经 settled 的 promise。 It performs the following steps when called:

  1. 断言:module 不是 Cyclic Module Record
  2. promisemodule.Evaluate()。
  3. 断言:promise.[[PromiseState]]fulfilledrejected
  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 Record

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

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

Table 41: Cyclic Module Record 的附加字段
字段名 值类型 含义
[[Status]] new, unlinked, linking, linked, evaluating, evaluating-async, or evaluated 初始为 new。随着模块在其生命周期中前进,依次转换为 unlinkedlinkinglinkedevaluating、可能为 evaluating-asyncevaluatedevaluating-async 表示此模块已排队等待其异步依赖项完成后执行,或者它是一个 [[HasTLA]] 字段为 true、已被执行且正在等待顶层完成的模块。
[[EvaluationError]] a throw completion or empty 表示求值期间发生的异常的 throw completion。如果没有发生异常,或 [[Status]] 不是 evaluated,则为 empty
[[DFSAncestorIndex]] an integer or empty 仅在 LinkEvaluate 期间使用的辅助字段。如果 [[Status]]linkingevaluating,则它要么是模块的深度优先遍历索引,要么是同一强连通分量中“更早”模块的深度优先遍历索引。
[[RequestedModules]] a List of ModuleRequest Records 与此模块中导入关联的 ModuleRequest RecordList。该 List 按导入在源文本中的出现顺序排列。
[[LoadedModules]] a List of LoadedModuleRequest Records 从由此 Record 表示的模块用于请求导入具有相对导入属性的模块的说明符字符串,到已解析 Module Record 的映射。该列表不包含两个不同的 Record r1r2,使得 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。它用于使从 Evaluate() 抽象方法返回的 Promise 对象 settled。对于该模块的任何依赖项,此字段将为 empty,除非已经为这些依赖项中的某些依赖项启动了顶层 Evaluate()。
[[AsyncParentModules]] a List of Cyclic Module Records 如果此模块或某个依赖项具有 [[HasTLA]] true,且执行正在进行中,则此字段为顶层执行作业跟踪此模块的父级导入者。这些父级模块不会在此模块成功完成执行之前开始执行。
[[PendingAsyncDependencies]] an integer or empty 如果此模块有任何异步依赖项,则此字段跟踪此模块剩余要执行的异步依赖模块数量。具有异步依赖项的模块会在此字段达到 0 且没有执行错误时执行。

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

Table 42: Cyclic Module Record 的附加抽象方法
方法 目的 定义
InitializeEnvironment ( )

The abstract method InitializeEnvironment takes no arguments and returns either a normal completion containing unused or a throw completion.

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

The abstract method ExecuteModule takes optional argument capability (a PromiseCapability Record) and returns either a normal completion containing unused or a throw completion.

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

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

Table 43: GraphLoadingState Record 字段
字段名 值类型 含义
[[PromiseCapability]] a PromiseCapability Record 加载过程结束时要 resolve 的 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 的具体方法,它们实现 Table 40 中定义的相应 Module Record 抽象方法。

16.2.1.6.1.1 LoadRequestedModules ( [ hostDefined ] )

The LoadRequestedModules concrete method of a Cyclic Module Record module takes optional argument hostDefined (anything) and returns a Promise. 它填充 module 的依赖图中所有 Module Record[[LoadedModules]](大部分工作由辅助函数 InnerModuleLoading 完成)。它接受一个可选的 hostDefined 参数,并将其传递给 HostLoadImportedModule hook。 It performs the following steps when called:

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

16.2.1.6.1.1.1 InnerModuleLoading ( state, module )

The abstract operation InnerModuleLoading takes arguments state (a GraphLoadingState Record) and module (a Module Record) and returns unused. LoadRequestedModules 使用它来为 module 的依赖图递归执行实际加载过程。 It performs the following steps when called:

  1. 断言:state.[[IsLoading]]true
  2. 如果 moduleCyclic Module Recordmodule.[[Status]]new,并且 state.[[Visited]]包含 module,则
    1. module 追加到 state.[[Visited]]
    2. requestedModulesCountmodule.[[RequestedModules]] 中元素的数量。
    3. state.[[PendingModulesCount]] 设置为 state.[[PendingModulesCount]] + requestedModulesCount
    4. module.[[RequestedModules]] 的每个 ModuleRequest Record request,执行:
      1. 如果 AllImportAttributesSupported(request.[[Attributes]]) 是 false,则
        1. errorThrowCompletion(一个新创建的 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 )

The abstract operation ContinueModuleLoading takes arguments state (a GraphLoadingState Record) and moduleCompletion (either a normal completion containing a Module Record or a throw completion) and returns unused. 它用于在调用 HostLoadImportedModule 后重新进入加载过程。 It performs the following steps when called:

  1. 如果 state.[[IsLoading]]false,则返回 unused
  2. 如果 moduleCompletion 是 normal completion,则
    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 ( )

The Link concrete method of a Cyclic Module Record module takes no arguments and returns either a normal completion containing unused or a throw completion. 成功时,Link 会将此模块的 [[Status]]unlinked 转换为 linked。失败时,会抛出异常,并且此模块的 [[Status]] 保持 unlinked。(大部分工作由辅助函数 InnerModuleLinking 完成。) It performs the following steps when called:

  1. 断言:module.[[Status]]unlinkedlinkedevaluating-asyncevaluated 之一。
  2. stack 为一个新的空 List
  3. resultCompletion(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]]linkedevaluating-asyncevaluated 之一。
  6. 断言:stack 为空。
  7. 返回 unused

16.2.1.6.1.2.1 InnerModuleLinking ( module, stack, index )

The abstract operation InnerModuleLinking takes arguments module (a Module Record), stack (a List of Cyclic Module Records), and index (a non-negative integer) and returns either a normal completion containing a non-negative integer or a throw completion. Link 使用它来为 module 执行实际链接过程,并递归地对依赖图中的所有其他模块执行实际链接过程。stackindex 参数,以及模块的 [[DFSAncestorIndex]] 字段,用于跟踪深度优先搜索(DFS)遍历。特别地,[[DFSAncestorIndex]] 用于发现强连通分量(SCC),使得一个 SCC 中的所有模块一起转换为 linked。 It performs the following steps when called:

  1. 如果 module 不是 Cyclic Module Record,则
    1. 执行 ? module.Link()。
    2. 返回 index
  2. 如果 module.[[Status]]linkinglinkedevaluating-asyncevaluated 之一,则
    1. 返回 index
  3. 断言:module.[[Status]]unlinked
  4. module.[[Status]] 设置为 linking
  5. moduleIndexindex
  6. module.[[DFSAncestorIndex]] 设置为 index
  7. index 设置为 index + 1。
  8. module 追加到 stack
  9. module.[[RequestedModules]] 的每个 ModuleRequest Record request,执行:
    1. requiredModuleGetImportedModule(module, request)。
    2. index 设置为 ? InnerModuleLinking(requiredModule, stack, index)。
    3. 如果 requiredModuleCyclic Module Record,则
      1. 断言:requiredModule.[[Status]]linkinglinkedevaluating-asyncevaluated 之一。
      2. 断言:当且仅当 stack 包含 requiredModule 时,requiredModule.[[Status]]linking
      3. 如果 requiredModule.[[Status]]linking,则
        1. module.[[DFSAncestorIndex]] 设置为 min(module.[[DFSAncestorIndex]], requiredModule.[[DFSAncestorIndex]])。
  10. 执行 ? module.InitializeEnvironment()。
  11. 断言:modulestack 中恰好出现一次。
  12. 断言:module.[[DFSAncestorIndex]]moduleIndex
  13. 如果 module.[[DFSAncestorIndex]] = moduleIndex,则
    1. donefalse
    2. 重复,只要 donefalse
      1. requiredModulestack 的最后一个元素。
      2. 移除 stack 的最后一个元素。
      3. 断言:requiredModuleCyclic Module Record
      4. requiredModule.[[Status]] 设置为 linked
      5. 如果 requiredModulemodule 是同一个 Module Record,则将 done 设置为 true
  14. 返回 index

16.2.1.6.1.3 Evaluate ( )

The Evaluate concrete method of a Cyclic Module Record module takes no arguments and returns a Promise. Evaluate 会将此模块的 [[Status]]linked 转换为 evaluating-asyncevaluated。第一次对给定强连通分量中的某个模块调用它时,Evaluate 会创建并返回一个 Promise,该 Promise 会在模块完成求值时 resolve。此 Promise 存储在该分量的 [[CycleRoot]][[TopLevelCapability]] 字段中。之后对该分量中任何模块调用 Evaluate,都会返回同一个 Promise。(大部分工作由辅助函数 InnerModuleEvaluation 完成。) It performs the following steps when called:

  1. 断言:对 Evaluate 的此调用不会与周围 agent 内对 Evaluate 的另一个调用同时发生。
  2. 断言:module.[[Status]]linkedevaluating-asyncevaluated 之一。
  3. 如果 module.[[Status]]evaluating-asyncevaluated,则
    1. 如果 module.[[CycleRoot]] 不是 empty,则
      1. module 设为 module.[[CycleRoot]]
    2. 否则,
      1. 断言:module.[[Status]]evaluated,且 module.[[EvaluationError]] 是一个 throw completion。
  4. 如果 module.[[TopLevelCapability]] 不是 empty,则
    1. 返回 module.[[TopLevelCapability]].[[Promise]]
  5. stack 为一个新的空 List
  6. promiseCapability 为 ! NewPromiseCapability(%Promise%)。
  7. module.[[TopLevelCapability]] 设为 promiseCapability
  8. resultCompletion(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-asyncevaluated
    2. 断言:module.[[EvaluationError]]empty
    3. 如果 module.[[Status]]evaluated,则
      1. 断言:module.[[AsyncEvaluationOrder]]unsetdone
      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 )

The abstract operation InnerModuleEvaluation takes arguments module (a Module Record), stack (a List of Cyclic Module Records), and index (a non-negative integer) and returns either a normal completion containing a non-negative integer or a throw completion. Evaluate 使用它来为 module 执行实际求值过程,并递归地对依赖图中的所有其他模块执行实际求值过程。stackindex 参数,以及 module[[DFSAncestorIndex]] 字段,其用法与 InnerModuleLinking 中相同。 It performs the following steps when called:

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

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

Note 2

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

16.2.1.6.1.3.2 ExecuteAsyncModule ( module )

The abstract operation ExecuteAsyncModule takes argument module (a Cyclic Module Record) and returns unused. It performs the following steps when called:

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

16.2.1.6.1.3.3 GatherAvailableAncestors ( module, execList )

The abstract operation GatherAvailableAncestors takes arguments module (a Cyclic Module Record) and execList (a List of Cyclic Module Records) and returns unused. It performs the following steps when called:

  1. module.[[AsyncParentModules]] 的每个 Cyclic Module Record ancestorModule,执行:
    1. 如果 execList包含 ancestorModuleancestorModule.[[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
Note

当根 module 的异步执行被 fulfilled 时,此函数会确定能够在此完成时一起同步执行的模块列表,并将其填充到 execList 中。

16.2.1.6.1.3.4 AsyncModuleExecutionFulfilled ( module )

The abstract operation AsyncModuleExecutionFulfilled takes argument module (a Cyclic Module Record) and returns unused. It performs the following steps when called:

  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. resultCompletion(ancestorModule.ExecuteModule())。
      2. 如果 result 是 abrupt completion,则
        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 )

The abstract operation AsyncModuleExecutionRejected takes arguments module (a Cyclic Module Record) and error (an ECMAScript language value) and returns unused. It performs the following steps when called:

  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 图示例

本非规范性小节给出一些常见模块图的链接和求值的一系列示例,并特别关注错误如何发生。

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

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

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

接下来考虑在成功调用 A.LoadRequestedModules() 之后发生链接错误的情况。如果 CInnerModuleLinking 成功,但之后 BInnerModuleLinking 失败,例如因为它导入了 C 未提供的某个内容,那么原始 A.Link() 将失败,并且 AB[[Status]] 都保持 unlinked。不过,C[[Status]] 已经变为 linked

最后,考虑在成功调用 Link() 之后发生求值错误的情况。如果 CInnerModuleEvaluation 成功,但之后 BInnerModuleEvaluation 失败,例如因为 B 包含会抛出异常的代码,那么原始 A.Evaluate() 将失败,返回一个 rejected Promise。所得异常将记录在 AB[[EvaluationError]] 字段中,并且它们的 [[Status]] 将变为 evaluatedC 也会变为 evaluated,但与 AB 不同,由于它成功完成了求值,它将保持没有 [[EvaluationError]]。存储异常确保宿主任何时候尝试通过调用 Evaluate() 方法重用 AB 时,都会遇到相同的异常。(宿主不需要重用 Cyclic Module Record;类似地,宿主不需要暴露由这些方法抛出的异常对象。不过,本规范允许这种用途。)

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

Figure 3: 带有无法解析模块的模块图
一个模块图,其中模块 A 依赖一个缺失(无法解析)的模块,用 ??? 表示

在此场景中,模块 A 声明了对某个其他模块的依赖,但不存在该模块的 Module Record,即当请求它时,HostLoadImportedModule 会用异常调用 FinishLoadingImportedModule。这可能由于各种原因发生,例如对应资源不存在,或资源存在但 ParseModule 在尝试解析所得源文本时返回一些错误。宿主可以选择通过传给 FinishLoadingImportedModule 的 completion 暴露失败原因。无论如何,此异常都会导致加载失败,从而使 A[[Status]] 保持 new

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

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

现在,考虑一个带有循环的模块图:

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

这里我们假设入口点是模块 A,因此宿主首先调用 A.LoadRequestedModules(),它会在 A 上执行 InnerModuleLoading。这又会在 BC 上调用 InnerModuleLoading。由于存在循环,这又会触发在 A 上调用 InnerModuleLoading,但此时它是 no-op,因为在此次 LoadRequestedModules 过程中 A 的依赖项加载已经被触发。当图中的所有模块都已成功加载时,它们的 [[Status]] 同时从 new 转换为 unlinked

然后宿主继续调用 A.Link(),它会在 A 上执行 InnerModuleLinking。这又会在 B 上调用 InnerModuleLinking。由于存在循环,这又会触发在 A 上调用 InnerModuleLinking,但此时它是 no-op,因为 A.[[Status]] 已经是 linking。当控制回到 A 并在 C 上触发 InnerModuleLinking 时,B.[[Status]] 自身仍保持 linking。在这返回且 C.[[Status]]linked 后,AB 一起从 linking 转换为 linked;这是有意设计的,因为它们形成一个强连通分量。能够同时转换同一 SCC 中模块的状态,是因为在此阶段模块图通过深度优先搜索遍历。

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

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

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

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

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

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

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

Table 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(BC 1(D 2(DE 0 0

让我们假设 E 最先完成执行。当这发生时,会调用 AsyncModuleExecutionFulfilledE.[[Status]] 会被设置为 evaluated,并且 C.[[PendingAsyncDependencies]] 会递减为 1。更新后的模块字段如 Table 45 所示。

Table 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 并行)。更新后的模块字段如 Table 46 所示。

Table 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 接下来完成执行。当这发生时,会再次调用 AsyncModuleExecutionFulfilledC.[[Status]] 会被设置为 evaluated,并且 A.[[PendingAsyncDependencies]] 会递减为 1。更新后的模块字段如 Table 47 所示。

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

然后,B 完成执行。当这发生时,会再次调用 AsyncModuleExecutionFulfilled,并且 B.[[Status]] 会被设置为 evaluatedA.[[PendingAsyncDependencies]] 会递减为 0,因此调用 ExecuteAsyncModule 并且它开始执行。更新后的模块字段如 Table 48 所示。

Table 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() 返回的)会被 resolve,并且这结束了对此模块图的处理。更新后的模块字段如 Table 49 所示。

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

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

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

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

Table 51: 模块 A 被 rejected 之后的模块字段
字段
模块
A
[[DFSAncestorIndex]] 0
[[Status]] evaluated
[[AsyncEvaluationOrder]] done
[[AsyncParentModules]] « »
[[PendingAsyncDependencies]] 0
[[EvaluationError]] CEvaluation Error

然后,B 完成执行且没有错误。当这发生时,会再次调用 AsyncModuleExecutionFulfilled,并且 B.[[Status]] 会被设置为 evaluated。会在 B 上调用 GatherAvailableAncestors。不过,A.[[CycleRoot]]A,且它有求值错误,因此它不会被添加到返回的 sortedExecList,并且 AsyncModuleExecutionFulfilled 将返回而不做进一步处理。B 的任何未来导入者都会从循环根 A 上设置的来自 C 的求值错误中,解析 B.[[CycleRoot]].[[EvaluationError]] 的拒绝。更新后的模块字段如 Table 52 所示。

Table 52: 错误图中模块 B 完成执行之后的模块字段
字段
模块
A B
[[DFSAncestorIndex]] 0 0
[[Status]] evaluated evaluated
[[AsyncEvaluationOrder]] 4 1
[[AsyncParentModules]] « » « A »
[[PendingAsyncDependencies]] 0 0
[[EvaluationError]] CEvaluation Error empty

16.2.1.7 Source Text Module Record

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

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

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

Table 53: Source Text Module Record 的附加字段
字段名 值类型 含义
[[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 RecordList
[[LocalExportEntries]] a List of ExportEntry Records 从此模块代码派生出的 ExportEntry RecordList,对应于模块内出现的声明。
[[IndirectExportEntries]] a List of ExportEntry Records 从此模块代码派生出的 ExportEntry RecordList,对应于模块内出现的重导出导入,或来自 export * as namespace 声明的导出。
[[StarExportEntries]] a List of ExportEntry Records 从此模块代码派生出的 ExportEntry RecordList,对应于模块内出现的 export * 声明,但不包括 export * as namespace 声明。

ImportEntry Record 是摘要化关于单个声明式导入的信息的 Record。每个 ImportEntry Record 都具有 Table 54 中定义的字段:

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

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

Table 55 (Informative): 导入形式到 ImportEntry Record 的映射
Import 语句形式 [[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 都具有 Table 56 中定义的字段:

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

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

Table 57 (Informative): 导出形式到 ExportEntry Record 的映射
Export 语句形式 [[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 )

The abstract operation ParseModule takes arguments sourceText (a String or a sequence of Unicode code points), realm (a Realm Record), and hostDefined (anything) and returns a Source Text Module Record or a non-empty List of SyntaxError objects. 它基于把 sourceText 解析为 Module 的结果创建一个 Source Text Module Record。 It performs the following steps when called:

  1. bodyParseText(sourceText, Module)。
  2. 如果 body 是错误 List,则返回 body
  3. requestedModulesbodyModuleRequests
  4. importEntriesbodyImportEntries
  5. importedBoundNamesImportedLocalNames(importEntries)。
  6. indirectExportEntries 为一个新的空 List
  7. localExportEntries 为一个新的空 List
  8. starExportEntries 为一个新的空 List
  9. exportEntriesbodyExportEntries
  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. importEntryimportEntries[[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. asyncbody 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 }。
Note

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

16.2.1.7.2 Module Record 抽象方法的实现

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

16.2.1.7.2.1 GetExportedNames ( [ exportStarSet ] )

The GetExportedNames concrete method of a Source Text Module Record module takes optional argument exportStarSet (a List of Source Text Module Records) and returns a List of Strings. It performs the following steps when called:

  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. requestedModuleGetImportedModule(module, exportEntry.[[ModuleRequest]])。
    3. starNamesrequestedModule.GetExportedNames(exportStarSet)。
    4. starNames 的每个元素 name,执行:
      1. 如果 name 不是 "default",则
        1. 如果 exportedNames包含 name,则
          1. name 追加到 exportedNames
  9. 返回 exportedNames
Note

GetExportedNames 不会过滤掉具有 ambiguous 星号导出绑定的名称,也不会对此抛出异常。

16.2.1.7.2.2 ResolveExport ( exportName [ , resolveSet ] )

The ResolveExport concrete method of a Source Text Module Record module takes argument exportName (a String) and optional argument resolveSet (a List of Records with fields [[Module]] (a Module Record) and [[ExportName]] (a String)) and returns a ResolvedBinding Record, null, or ambiguous.

ResolveExport 尝试将导入绑定解析为实际定义该绑定的模块和本地绑定名称。定义模块可以是调用此方法的 Module Record 所表示的模块,也可以是由该模块导入的某个其他模块。参数 resolveSet 用于检测未解析的循环导入/导出路径。如果到达一个由特定 Module RecordexportName 组成、且已经在 resolveSet 中的 pair,就遇到了导入循环性。在递归调用 ResolveExport 之前,会把由 moduleexportName 组成的 pair 添加到 resolveSet

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

It performs the following steps when called:

  1. 断言:module.[[Status]] 不是 new
  2. 如果 resolveSet 不存在,则将 resolveSet 设为一个新的空 List
  3. resolveSet 的每个 Record { [[Module]], [[ExportName]] } record,执行:
    1. 如果 modulerecord.[[Module]] 是同一个 Module Record,且 exportNamerecord.[[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. importedModuleGetImportedModule(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. starResolutionnull
  9. module.[[StarExportEntries]] 的每个 ExportEntry Record exportEntry,执行:
    1. 断言:exportEntry.[[ModuleRequest]] 不是 null
    2. importedModuleGetImportedModule(module, exportEntry.[[ModuleRequest]])。
    3. resolutionimportedModule.ResolveExport(exportName, resolveSet)。
    4. 如果 resolutionambiguous,则返回 ambiguous
    5. 如果 resolution 不是 null,则
      1. 断言:resolution 是一个 ResolvedBinding Record
      2. 如果 starResolutionnull,则
        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 的具体方法,它们实现 Table 42 中定义的相应 Cyclic Module Record 抽象方法。

16.2.1.7.3.1 InitializeEnvironment ( )

The InitializeEnvironment concrete method of a Source Text Module Record module takes no arguments and returns either a normal completion containing unused or a throw completion. It performs the following steps when called:

  1. module.[[IndirectExportEntries]] 的每个 ExportEntry Record exportEntry,执行:
    1. 断言:exportEntry.[[ExportName]] 不是 null
    2. resolutionmodule.ResolveExport(exportEntry.[[ExportName]])。
    3. 如果 resolutionnullambiguous,则抛出一个 SyntaxError 异常。
    4. 断言:resolution 是一个 ResolvedBinding Record
  2. 断言:来自 module 的所有具名导出都是可解析的。
  3. realmmodule.[[Realm]]
  4. 断言:realm 不是 undefined
  5. envRecordNewModuleEnvironment(realm.[[GlobalEnv]])。
  6. module.[[Environment]] 设为 envRecord
  7. module.[[ImportEntries]] 的每个 ImportEntry Record importEntry,执行:
    1. importedModuleGetImportedModule(module, importEntry.[[ModuleRequest]])。
    2. 如果 importEntry.[[ImportName]]namespace,则
      1. namespaceGetModuleNamespace(importedModule)。
      2. 执行 ! envRecord.CreateImmutableBinding(importEntry.[[LocalName]], true)。
      3. 执行 ! envRecord.InitializeBinding(importEntry.[[LocalName]], namespace)。
    3. 否则,
      1. 断言:importEntry.[[ImportName]] 是一个 String。
      2. resolutionimportedModule.ResolveExport(importEntry.[[ImportName]])。
      3. 如果 resolutionnullambiguous,则抛出一个 SyntaxError 异常。
      4. 如果 resolution.[[BindingName]]namespace,则
        1. namespaceGetModuleNamespace(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. moduleContextRealm 设为 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. codemodule.[[ECMAScriptCode]]
  19. variableDeclscodeVarScopedDeclarations
  20. declaredVariableNames 为一个新的空 List
  21. variableDecls 的每个元素 variableDecl,执行:
    1. variableDeclBoundNames 的每个元素 name,执行:
      1. 如果 declaredVariableNames包含 name,则
        1. 执行 ! envRecord.CreateMutableBinding(name, false)。
        2. 执行 ! envRecord.InitializeBinding(name, undefined)。
        3. name 追加到 declaredVariableNames
  22. lexicalDeclscodeLexicallyScopedDeclarations
  23. privateEnvnull
  24. lexicalDecls 的每个元素 lexicalDecl,执行:
    1. lexicalDeclBoundNames 的每个元素 name,执行:
      1. 如果 lexicalDeclIsConstantDeclarationtrue,则
        1. 执行 ! envRecord.CreateImmutableBinding(name, true)。
      2. 否则,
        1. 执行 ! envRecord.CreateMutableBinding(name, false)。
      3. 如果 lexicalDeclFunctionDeclarationGeneratorDeclarationAsyncFunctionDeclarationAsyncGeneratorDeclaration,则
        1. funcObj 为使用参数 envRecordprivateEnvlexicalDecl 执行 InstantiateFunctionObject 的结果。
        2. 执行 ! envRecord.InitializeBinding(name, funcObj)。
  25. 从执行上下文栈中移除 moduleContext
  26. 返回 unused

16.2.1.7.3.2 ExecuteModule ( [ capability ] )

The ExecuteModule concrete method of a Source Text Module Record module takes optional argument capability (a PromiseCapability Record) and returns either a normal completion containing unused or a throw completion. It performs the following steps when called:

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

16.2.1.8 Synthetic Module Record

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

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

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

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

16.2.1.8.1 CreateDefaultExportSyntheticModule ( defaultExport )

The abstract operation CreateDefaultExportSyntheticModule takes argument defaultExport (an ECMAScript language value) and returns a Synthetic Module Record. 它创建一个默认导出为 defaultExportSynthetic Module Record。 It performs the following steps when called:

  1. realm当前 Realm Record
  2. setDefaultExport 为一个新的 Abstract Closure,它具有参数 (module)、捕获 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 )

The abstract operation ParseJSONModule takes argument source (a String) and returns either a normal completion containing a Synthetic Module Record, or a throw completion. It performs the following steps when called:

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

16.2.1.8.3 SetSyntheticModuleExport ( module, exportName, exportValue )

The abstract operation SetSyntheticModuleExport takes arguments module (a Synthetic Module Record), exportName (a String), and exportValue (an ECMAScript language value) and returns unused. 它可用于为 Synthetic Module Record 的现有导出设置或更改导出值。 It performs the following steps when called:

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

16.2.1.8.4 Module Record 抽象方法的实现

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

16.2.1.8.4.1 LoadRequestedModules ( [ hostDefined ] )

The LoadRequestedModules concrete method of a Synthetic Module Record module takes optional argument hostDefined (anything) and returns a Promise. It performs the following steps when called:

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

16.2.1.8.4.2 GetExportedNames ( [ exportStarSet ] )

The GetExportedNames concrete method of a Synthetic Module Record module takes optional argument exportStarSet (a List of Source Text Module Records) and returns a List of Strings. It performs the following steps when called:

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

16.2.1.8.4.3 ResolveExport ( exportName [ , resolveSet ] )

The ResolveExport concrete method of a Synthetic Module Record module takes argument exportName (a String) and optional argument resolveSet (a List of Records with fields [[Module]] (a Module Record) and [[ExportName]] (a String)) and returns a ResolvedBinding Record, null, or ambiguous. It performs the following steps when called:

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

16.2.1.8.4.4 Link ( )

The Link concrete method of a Synthetic Module Record module takes no arguments and returns a normal completion containing unused. It performs the following steps when called:

  1. realmmodule.[[Realm]]
  2. envRecordNewModuleEnvironment(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 ( )

The Evaluate concrete method of a Synthetic Module Record module takes no arguments and returns a Promise. It performs the following steps when called:

  1. moduleContext 为新的 ECMAScript 代码执行上下文
  2. moduleContext 的 Function 设置为 null
  3. moduleContextRealm 设置为 module.[[Realm]]
  4. moduleContext 的 ScriptOrModule 设置为 module
  5. moduleContext 的 VariableEnvironment 设置为 module.[[Environment]]
  6. moduleContext 的 LexicalEnvironment 设置为 module.[[Environment]]
  7. 挂起运行中的执行上下文。
  8. moduleContext 压入执行上下文栈;moduleContext 现在是运行中的执行上下文。
  9. stepsmodule.[[EvaluationSteps]]
  10. resultCompletion(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 )

The abstract operation GetImportedModule takes arguments referrer (a Cyclic Module Record) and request (a ModuleRequest Record) and returns a Module Record. It performs the following steps when called:

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

16.2.1.10 HostLoadImportedModule ( referrer, moduleRequest, hostDefined, payload )

The host-defined abstract operation HostLoadImportedModule takes arguments referrer (a Script Record, a Cyclic Module Record, or a Realm Record), moduleRequest (a ModuleRequest Record), hostDefined (anything), and payload (a GraphLoadingState Record or a PromiseCapability Record) and returns unused.

Note 1

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

<button type="button" onclick="import('./foo.mjs')">Click me</button>

则在 import() 表达式运行时,将没有活动脚本或模块。更一般地说,这可能发生在宿主把 ScriptOrModule 组件为 null 的执行上下文压入执行上下文栈的任何情况下。

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

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

Note 2

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

16.2.1.11 FinishLoadingImportedModule ( referrer, moduleRequest, payload, result )

The abstract operation FinishLoadingImportedModule takes arguments referrer (a Script Record, a Cyclic Module Record, or a Realm Record), moduleRequest (a ModuleRequest Record), payload (a GraphLoadingState Record or a PromiseCapability Record), and result (either a normal completion containing a Module Record or a throw completion) and returns unused. It performs the following steps when called:

  1. 如果 result 是 normal completion,则
    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. 如果 payloadGraphLoadingState Record,则
    1. 执行 ContinueModuleLoading(payload, result)。
  3. 否则,
    1. 执行 ContinueDynamicImport(payload, result)。
  4. 返回 unused

16.2.1.12 AllImportAttributesSupported ( attrs )

The abstract operation AllImportAttributesSupported takes argument attrs (a List of ImportAttribute Records) and returns a Boolean. It performs the following steps when called:

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

16.2.1.12.1 HostGetSupportedImportAttributes ( )

The host-defined abstract operation HostGetSupportedImportAttributes takes no arguments and returns a List of Strings. 它允许宿主环境指定它们支持哪些导入属性。只有带有受支持键的属性才会提供给宿主

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

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

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

Note
要求宿主指定其支持的导入属性,而不是把所有属性传给宿主然后让宿主选择想处理哪些属性,其目的是确保在不同宿主中以一致方式处理不受支持的属性。

16.2.1.13 GetModuleNamespace ( module )

The abstract operation GetModuleNamespace takes argument module (an instance of a concrete subclass of Module Record) and returns a Module Namespace Object. 它取得表示 module 导出的 Module Namespace Object,在首次请求时惰性创建它,并将其存储在 module.[[Namespace]] 中以供将来取得。 It performs the following steps when called:

  1. 断言:如果 moduleCyclic Module Record,则 module.[[Status]] 不是 newunlinked
  2. namespacemodule.[[Namespace]]
  3. 如果 namespaceempty,则
    1. exportedNamesmodule.GetExportedNames()。
    2. unambiguousNames 为新的空 List
    3. exportedNames 的每个元素 name,执行:
      1. resolutionmodule.ResolveExport(name)。
      2. 如果 resolutionResolvedBinding Record,则将 name 追加到 unambiguousNames
    4. namespace 设置为 ModuleNamespaceCreate(module, unambiguousNames)。
  4. 返回 namespace
Note

GetModuleNamespace 永远不会抛出。相反,无法解析的名称只是在此时从 namespace 中排除。它们稍后会导致真正的链接错误,除非它们全都是未在任何地方被显式请求的 ambiguous 星号导出。

16.2.1.14 Runtime Semantics: Evaluation

Module : [empty]
  1. 返回 undefined
ModuleBody : ModuleItemList
  1. resultCompletion(ModuleItemListEvaluation)。
  2. 如果 result 是 normal completion 且 result.[[Value]]empty,则
    1. 返回 undefined
  3. 返回 ? result
ModuleItemList : ModuleItemList ModuleItem
  1. sl 为 ? ModuleItemListEvaluation
  2. sCompletion(ModuleItemEvaluation)。
  3. 返回 ? UpdateEmpty(s, sl)。
Note

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 } { ImportsList , } 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

The syntax-directed operation ImportEntries takes no arguments and returns a List of ImportEntry Records. It is defined piecewise over the following productions:

Module : [empty]
  1. 返回新的空 List
ModuleItemList : ModuleItemList ModuleItem
  1. entries1ModuleItemListImportEntries
  2. entries2ModuleItemImportEntries
  3. 返回 entries1entries2列表连接
ModuleItem : ExportDeclaration StatementListItem
  1. 返回新的空 List
ImportDeclaration : import ImportClause FromClause WithClauseopt ;
  1. moduleImportDeclarationModuleRequests 的唯一元素。
  2. 返回以 module 为实参执行 ImportClauseImportEntriesForModule
ImportDeclaration : import ModuleSpecifier WithClauseopt ;
  1. 返回新的空 List

16.2.2.3 Static Semantics: ImportEntriesForModule

The syntax-directed operation ImportEntriesForModule takes argument module (a ModuleRequest Record) and returns a List of ImportEntry Records. It is defined piecewise over the following productions:

ImportClause : ImportedDefaultBinding , NameSpaceImport
  1. entries1 为以 module 为实参执行 ImportedDefaultBindingImportEntriesForModule
  2. entries2 为以 module 为实参执行 NameSpaceImportImportEntriesForModule
  3. 返回 entries1entries2列表连接
ImportClause : ImportedDefaultBinding , NamedImports
  1. entries1 为以 module 为实参执行 ImportedDefaultBindingImportEntriesForModule
  2. entries2 为以 module 为实参执行 NamedImportsImportEntriesForModule
  3. 返回 entries1entries2列表连接
ImportedDefaultBinding : ImportedBinding
  1. localNameImportedBindingBoundNames 的唯一元素。
  2. defaultEntryImportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: "default", [[LocalName]]: localName }。
  3. 返回 « defaultEntry »。
NameSpaceImport : * as ImportedBinding
  1. localNameImportedBindingStringValue
  2. entryImportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: namespace, [[LocalName]]: localName }。
  3. 返回 « entry »。
NamedImports : { }
  1. 返回新的空 List
ImportsList : ImportsList , ImportSpecifier
  1. specs1 为以 module 为实参执行 ImportsListImportEntriesForModule
  2. specs2 为以 module 为实参执行 ImportSpecifierImportEntriesForModule
  3. 返回 specs1specs2列表连接
ImportSpecifier : ImportedBinding
  1. localNameImportedBindingBoundNames 的唯一元素。
  2. entryImportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: localName, [[LocalName]]: localName }。
  3. 返回 « entry »。
ImportSpecifier : ModuleExportName as ImportedBinding
  1. importNameModuleExportNameStringValue
  2. localNameImportedBindingStringValue
  3. entryImportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: importName, [[LocalName]]: localName }。
  4. 返回 « entry »。

16.2.2.4 Static Semantics: WithClauseToAttributes

The syntax-directed operation WithClauseToAttributes takes no arguments and returns a List of ImportAttribute Records. It is defined piecewise over the following productions:

WithClause : with { }
  1. 返回新的空 List
WithClause : with { WithEntries ,opt }
  1. attrsWithEntriesWithClauseToAttributes
  2. 根据 attrs[[Key]] 字段的字典序对 attrs 排序,把每个此类字段的值视为 UTF-16 码元值序列。注:此排序唯一可观察之处在于,宿主被禁止基于枚举属性的顺序来改变行为。
  3. 返回 attrs
WithEntries : AttributeKey : StringLiteral
  1. keyAttributeKeyPropName
  2. entryImportAttribute Record { [[Key]]: key, [[Value]]: StringLiteralSV }。
  3. 返回 « entry »。
WithEntries : AttributeKey : StringLiteral , WithEntries
  1. keyAttributeKeyPropName
  2. entryImportAttribute Record { [[Key]]: key, [[Value]]: StringLiteralSV }。
  3. restWithEntriesWithClauseToAttributes
  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 } { ExportsList , } ExportsList : ExportSpecifier ExportsList , ExportSpecifier ExportSpecifier : ModuleExportName ModuleExportName as ModuleExportName

16.2.3.1 Static Semantics: 早期错误

ExportDeclaration : export NamedExports ; Note

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

16.2.3.2 Static Semantics: ExportedBindings

The syntax-directed operation ExportedBindings takes no arguments and returns a List of Strings.

Note

ExportedBindings 是与 ModuleExportedNames 显式关联的本地绑定名称。

It is defined piecewise over the following productions:

ModuleItemList : ModuleItemList ModuleItem
  1. names1ModuleItemListExportedBindings
  2. names2ModuleItemExportedBindings
  3. 返回 names1names2列表连接
ModuleItem : ImportDeclaration StatementListItem
  1. 返回新的空 List
ExportDeclaration : export ExportFromClause FromClause WithClauseopt ;
  1. 返回新的空 List
ExportDeclaration : export NamedExports ;
  1. 返回 NamedExportsExportedBindings
ExportDeclaration : export VariableStatement
  1. 返回 VariableStatementBoundNames
ExportDeclaration : export Declaration
  1. 返回 DeclarationBoundNames
ExportDeclaration : export default HoistableDeclaration export default ClassDeclaration export default AssignmentExpression ;
  1. 返回此 ExportDeclarationBoundNames
NamedExports : { }
  1. 返回新的空 List
ExportsList : ExportsList , ExportSpecifier
  1. names1ExportsListExportedBindings
  2. names2ExportSpecifierExportedBindings
  3. 返回 names1names2列表连接
ExportSpecifier : ModuleExportName
  1. 返回一个 List,其唯一元素为 ModuleExportNameStringValue
ExportSpecifier : ModuleExportName as ModuleExportName
  1. 返回一个 List,其唯一元素为第一个 ModuleExportNameStringValue

16.2.3.3 Static Semantics: ExportedNames

The syntax-directed operation ExportedNames takes no arguments and returns a List of Strings.

Note

ExportedNames 是外部可见名称,Module 会显式地将其映射到自己的某个本地名称绑定。

It is defined piecewise over the following productions:

ModuleItemList : ModuleItemList ModuleItem
  1. names1ModuleItemListExportedNames
  2. names2ModuleItemExportedNames
  3. 返回 names1names2列表连接
ModuleItem : ExportDeclaration
  1. 返回 ExportDeclarationExportedNames
ModuleItem : ImportDeclaration StatementListItem
  1. 返回新的空 List
ExportDeclaration : export ExportFromClause FromClause WithClauseopt ;
  1. 返回 ExportFromClauseExportedNames
ExportFromClause : *
  1. 返回新的空 List
ExportFromClause : * as ModuleExportName
  1. 返回一个 List,其唯一元素为 ModuleExportNameStringValue
ExportFromClause : NamedExports
  1. 返回 NamedExportsExportedNames
ExportDeclaration : export VariableStatement
  1. 返回 VariableStatementBoundNames
ExportDeclaration : export Declaration
  1. 返回 DeclarationBoundNames
ExportDeclaration : export default HoistableDeclaration export default ClassDeclaration export default AssignmentExpression ;
  1. 返回 « "default" »。
NamedExports : { }
  1. 返回新的空 List
ExportsList : ExportsList , ExportSpecifier
  1. names1ExportsListExportedNames
  2. names2ExportSpecifierExportedNames
  3. 返回 names1names2列表连接
ExportSpecifier : ModuleExportName
  1. 返回一个 List,其唯一元素为 ModuleExportNameStringValue
ExportSpecifier : ModuleExportName as ModuleExportName
  1. 返回一个 List,其唯一元素为第二个 ModuleExportNameStringValue

16.2.3.4 Static Semantics: ExportEntries

The syntax-directed operation ExportEntries takes no arguments and returns a List of ExportEntry Records. It is defined piecewise over the following productions:

Module : [empty]
  1. 返回新的空 List
ModuleItemList : ModuleItemList ModuleItem
  1. entries1ModuleItemListExportEntries
  2. entries2ModuleItemExportEntries
  3. 返回 entries1entries2列表连接
ModuleItem : ImportDeclaration StatementListItem
  1. 返回新的空 List
ExportDeclaration : export ExportFromClause FromClause WithClauseopt ;
  1. moduleExportDeclarationModuleRequests 的唯一元素。
  2. 返回以 module 为实参执行 ExportFromClauseExportEntriesForModule
ExportDeclaration : export NamedExports ;
  1. 返回以 null 为实参执行 NamedExportsExportEntriesForModule
ExportDeclaration : export VariableStatement
  1. entries 为新的空 List
  2. namesVariableStatementBoundNames
  3. names 的每个元素 name,执行:
    1. ExportEntry Record { [[ModuleRequest]]: null, [[ImportName]]: null, [[LocalName]]: name, [[ExportName]]: name } 追加到 entries
  4. 返回 entries
ExportDeclaration : export Declaration
  1. entries 为新的空 List
  2. namesDeclarationBoundNames
  3. names 的每个元素 name,执行:
    1. ExportEntry Record { [[ModuleRequest]]: null, [[ImportName]]: null, [[LocalName]]: name, [[ExportName]]: name } 追加到 entries
  4. 返回 entries
ExportDeclaration : export default HoistableDeclaration
  1. namesHoistableDeclarationBoundNames
  2. localNamenames 的唯一元素。
  3. 返回一个 List,其唯一元素为新的 ExportEntry Record { [[ModuleRequest]]: null, [[ImportName]]: null, [[LocalName]]: localName, [[ExportName]]: "default" }。
ExportDeclaration : export default ClassDeclaration
  1. namesClassDeclarationBoundNames
  2. localNamenames 的唯一元素。
  3. 返回一个 List,其唯一元素为新的 ExportEntry Record { [[ModuleRequest]]: null, [[ImportName]]: null, [[LocalName]]: localName, [[ExportName]]: "default" }。
ExportDeclaration : export default AssignmentExpression ;
  1. entryExportEntry Record { [[ModuleRequest]]: null, [[ImportName]]: null, [[LocalName]]: "*default*", [[ExportName]]: "default" }。
  2. 返回 « entry »。
Note

"*default*" 在本规范内用作匿名默认导出值的合成名称。更多细节见此注

16.2.3.5 Static Semantics: ExportEntriesForModule

The syntax-directed operation ExportEntriesForModule takes argument module (a ModuleRequest Record or null) and returns a List of ExportEntry Records. It is defined piecewise over the following productions:

ExportFromClause : *
  1. entryExportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: all-but-default, [[LocalName]]: null, [[ExportName]]: null }。
  2. 返回 « entry »。
ExportFromClause : * as ModuleExportName
  1. exportNameModuleExportNameStringValue
  2. entryExportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: namespace, [[LocalName]]: null, [[ExportName]]: exportName }。
  3. 返回 « entry »。
NamedExports : { }
  1. 返回新的空 List
ExportsList : ExportsList , ExportSpecifier
  1. specs1 为以 module 为实参执行 ExportsListExportEntriesForModule
  2. specs2 为以 module 为实参执行 ExportSpecifierExportEntriesForModule
  3. 返回 specs1specs2列表连接
ExportSpecifier : ModuleExportName
  1. sourceNameModuleExportNameStringValue
  2. 如果 modulenull,则
    1. localNamesourceName
    2. importNamenull
  3. 否则,
    1. localNamenull
    2. importNamesourceName
  4. 返回一个 List,其唯一元素为新的 ExportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: importName, [[LocalName]]: localName, [[ExportName]]: sourceName }。
ExportSpecifier : ModuleExportName as ModuleExportName
  1. sourceName 为第一个 ModuleExportNameStringValue
  2. exportName 为第二个 ModuleExportNameStringValue
  3. 如果 modulenull,则
    1. localNamesourceName
    2. importNamenull
  4. 否则,
    1. localNamenull
    2. importNamesourceName
  5. 返回一个 List,其唯一元素为新的 ExportEntry Record { [[ModuleRequest]]: module, [[ImportName]]: importName, [[LocalName]]: localName, [[ExportName]]: exportName }。

16.2.3.6 Static Semantics: ReferencedBindings

The syntax-directed operation ReferencedBindings takes no arguments and returns a List of Parse Nodes. It is defined piecewise over the following productions:

NamedExports : { }
  1. 返回新的空 List
ExportsList : ExportsList , ExportSpecifier
  1. names1ExportsListReferencedBindings
  2. names2ExportSpecifierReferencedBindings
  3. 返回 names1names2列表连接
ExportSpecifier : ModuleExportName as ModuleExportName
  1. 返回第一个 ModuleExportNameReferencedBindings
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. 返回 ? VariableStatementEvaluation
ExportDeclaration : export Declaration
  1. 返回 ? DeclarationEvaluation
ExportDeclaration : export default HoistableDeclaration
  1. 返回 ? HoistableDeclarationEvaluation
ExportDeclaration : export default ClassDeclaration
  1. value 为 ? ClassDeclarationBindingClassDeclarationEvaluation
  2. classNameClassDeclarationBoundNames 的唯一元素。
  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 为 ? AssignmentExpressionEvaluation
    2. value 为 ? GetValue(rhs)。
  3. envRecord 为运行中执行上下文的 LexicalEnvironment。
  4. 执行 ? InitializeBoundName("*default*", value, envRecord)。
  5. 返回 empty