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 一个布尔值. It is defined piecewise over the following productions:

Script : ScriptBodyopt
  1. 如果 ScriptBody 存在,且 ScriptBody 的 Directive 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 34 中列出的字段。

Table 34: Script Record Fields
字段名 值类型 含义
[[Realm]] 一个 Realm Record 创建此脚本所在的 realm
[[ECMAScriptCode]] 一个 Script 解析节点 解析此脚本源文本的结果。
[[LoadedModules]] LoadedModuleRequest RecordList 从此脚本导入的说明符字符串到已解析 Module Record 的映射。该列表不包含两个不同的 Record r1r2,使得 ModuleRequestsEqual(r1, r2) 为 true
[[HostDefined]] 任何值(默认值为 empty 保留给需要将额外信息与脚本关联的宿主环境使用的字段。

16.1.5 ParseScript ( sourceText, realm, hostDefined )

The abstract operation ParseScript takes arguments sourceText (ECMAScript 源文本), realm (一个 Realm Record), and hostDefined (任何值) and returns 一个 Script RecordSyntaxError 对象的非空 List. 它基于将 sourceText 解析为 Script 的结果创建一个 Script Record。 It performs the following steps when called:

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

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

16.1.6 ScriptEvaluation ( scriptRecord )

The abstract operation ScriptEvaluation takes argument scriptRecord (一个 Script Record) and returns 要么是包含一个 ECMAScript 语言值正常完成,要么是突然完成. 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. scriptscriptRecord.[[ECMAScriptCode]]
  12. resultCompletion(GlobalDeclarationInstantiation(script, globalEnv))。
  13. 如果 result正常完成,则
    1. result 设为 Completion(scriptEvaluation)。
    2. 如果 result正常完成result.[[Value]]empty,则
      1. result 设为 NormalCompletion(undefined)。
  14. 挂起 scriptContext 并将其从执行上下文栈中移除。
  15. 断言:执行上下文栈不为空。
  16. 恢复现在位于执行上下文栈顶部的上下文作为运行中执行上下文
  17. 返回 ? result

16.1.7 GlobalDeclarationInstantiation ( script, env )

The abstract operation GlobalDeclarationInstantiation takes arguments script (一个 Script 解析节点) and env (一个 Global Environment Record) and returns 要么是包含 unused正常完成,要么是抛出完成. script 是正在为其建立执行上下文Scriptenv 是将在其中创建绑定的全局环境。

Note 1

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

调用时执行以下步骤:

  1. lexNamesscriptLexicallyDeclaredNames
  2. varNamesscriptVarDeclaredNames
  3. lexNames 的每个元素 name,执行
    1. 如果 HasLexicalDeclaration(env, name) 为 true,抛出 SyntaxError 异常。
    2. hasRestrictedGlobal 为 ? HasRestrictedGlobalProperty(env, name)。
    3. 注:全局 varfunction 绑定(由非严格直接 eval 引入的除外)是不可配置的,因此是受限制的全局属性。
    4. 如果 hasRestrictedGlobaltrue,抛出 SyntaxError 异常。
  4. varNames 的每个元素 name,执行
    1. 如果 HasLexicalDeclaration(env, name) 为 true,抛出 SyntaxError 异常。
  5. varDeclarationsscriptVarScopedDeclarations
  6. functionsToInitialize 为一个新的空 List
  7. declaredFunctionNames 为一个新的空 List
  8. varDeclarations 的每个元素 varDecl,按 List 逆序执行
    1. 如果 varDecl 不是 VariableDeclarationForBindingBindingIdentifier 中的任一者,则
      1. 断言:varDeclFunctionDeclarationGeneratorDeclarationAsyncFunctionDeclarationAsyncGeneratorDeclaration 中的任一者。
      2. 注:如果同一名称有多个函数声明,则使用最后一个声明。
      3. fnvarDeclBoundNames 的唯一元素。
      4. 如果 declaredFunctionNames 不包含 fn,则
        1. fnDefinable 为 ? CanDeclareGlobalFunction(env, fn)。
        2. 如果 fnDefinablefalse,抛出 TypeError 异常。
        3. fn 追加到 declaredFunctionNames
        4. varDecl 插入为 functionsToInitialize 的第一个元素。
  9. declaredVarNames 为一个新的空 List
  10. varDeclarations 的每个元素 varDecl,执行
    1. 如果 varDeclVariableDeclarationForBindingBindingIdentifier 中的任一者,则
      1. varDeclBoundNames 的每个 String vn,执行
        1. 如果 declaredFunctionNames 不包含 vn,则
          1. vnDefinable 为 ? CanDeclareGlobalVar(env, vn)。
          2. 如果 vnDefinablefalse,抛出 TypeError 异常。
          3. 如果 declaredVarNames 不包含 vn,则
            1. vn 追加到 declaredVarNames
  11. 注:如果全局对象普通对象,则此算法步骤之后不会发生异常终止。然而,如果全局对象Proxy 异质对象,它可能表现出在以下某些步骤中导致异常终止的行为。
  12. Normative Optional
    如果宿主是 Web 浏览器或以其他方式支持 块级函数声明的 Web 遗留兼容性语义,则
    1. strictscriptScriptIsStrict
    2. 如果 strictfalse,则
      1. declaredFunctionOrVarNamesdeclaredFunctionNamesdeclaredVarNames 的列表拼接。
      2. 对直接包含于任何 BlockCaseClauseDefaultClause xStatementList 中,且 script Contains xtrue 的每个 FunctionDeclaration f,执行
        1. funcNamefBindingIdentifierStringValue
        2. 如果将 FunctionDeclaration f 替换为以 funcName 作为 BindingIdentifierVariableStatement 不会为 script 产生任何 Early Errors,则
          1. 如果 HasLexicalDeclaration(env, funcName) 为 false,则
            1. fnDefinable 为 ? CanDeclareGlobalVar(env, funcName)。
            2. 如果 fnDefinabletrue,则
              1. 注:只有当 funcName 既不是 VarDeclaredName 也不是另一个 FunctionDeclaration 的名称时,才在此实例化它的 var 绑定。
              2. 如果 declaredFunctionOrVarNames 不包含 funcName,则
                1. 执行 ? CreateGlobalVarBinding(env, funcName, false)。
                2. funcName 追加到 declaredFunctionOrVarNames
              3. FunctionDeclaration f 被求值时,执行以下步骤来替代 15.2.6 中提供的 FunctionDeclaration Evaluation 算法:
                1. gEnv 为运行中执行上下文的 VariableEnvironment。
                2. bEnv 为运行中执行上下文的 LexicalEnvironment。
                3. fObj 为 ! bEnv.GetBindingValue(funcName, false)。
                4. 执行 ? gEnv.SetMutableBinding(funcName, fObj, false)
                5. 返回 unused
  13. lexDeclarationsscriptLexicallyScopedDeclarations
  14. privateEnvnull
  15. lexDeclarations 的每个元素 lexDecl,执行
    1. 注:词法声明名称只在此实例化,而不初始化。
    2. lexDeclBoundNames 的每个元素 dn,执行
      1. 如果 lexDeclIsConstantDeclarationtrue,则
        1. 执行 ? env.CreateImmutableBinding(dn, true)
      2. 否则,
        1. 执行 ? env.CreateMutableBinding(dn, false)
  16. functionsToInitialize 的每个解析节点 f,执行
    1. fnfBoundNames 的唯一元素。
    2. fo 为以 envprivateEnv 为参数的 fInstantiateFunctionObject
    3. 执行 ? CreateGlobalFunctionBinding(env, fn, fo, false)。
  17. declaredVarNames 的每个 String vn,执行
    1. 执行 ? CreateGlobalVarBinding(env, vn, false)。
  18. 返回 unused
Note 2

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

与显式 var 或 function 声明不同,直接在全局对象上创建的属性会产生可被 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 (ImportEntry RecordList) and returns String 的 List. 它创建一个由 importEntries 定义的所有本地名称绑定组成的 List。 It performs the following steps when called:

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

16.2.1.3 ModuleRequest Records

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

Table 35: ModuleRequest Record Fields
字段名 值类型 含义
[[Specifier]] 一个 String 模块说明符
[[Attributes]] ImportAttribute RecordList 导入属性

LoadedModuleRequest Record 表示导入模块的请求以及产生的 Module Record。它由表 Table 35 中定义的相同字段组成,并额外包含 [[Module]]

Table 36: LoadedModuleRequest Record Fields
字段名 值类型 含义
[[Specifier]] 一个 String 模块说明符
[[Attributes]] ImportAttribute RecordList 导入属性
[[Module]] 一个 Module Record 与此模块请求对应的已加载模块

ImportAttribute Record 由以下字段组成:

Table 37: ImportAttribute Record Fields
字段名 值类型 含义
[[Key]] 一个 String 属性键
[[Value]] 一个 String 属性值

16.2.1.3.1 ModuleRequestsEqual ( left, right )

The abstract operation ModuleRequestsEqual takes arguments left (一个 ModuleRequest RecordLoadedModuleRequest Record) and right (一个 ModuleRequest RecordLoadedModuleRequest Record) and returns 一个布尔值. It performs the following steps when called:

  1. 如果 left.[[Specifier]] 不是 right.[[Specifier]],返回 false
  2. leftAttrsleft.[[Attributes]]
  3. rightAttrsright.[[Attributes]]
  4. leftAttrsCountleftAttrs 中的元素数量。
  5. rightAttrsCountrightAttrs 中的元素数量。
  6. 如果 leftAttrsCountrightAttrsCount,返回 false
  7. leftAttrs 的每个 ImportAttribute Record l,执行
    1. 如果 rightAttrs 不包含一个 ImportAttribute Record r,使得 l.[[Key]] 等于 r.[[Key]]l.[[Value]] 等于 r.[[Value]],返回 false
  8. 返回 true

16.2.1.4 Static Semantics: ModuleRequests

The syntax-directed operation ModuleRequests takes no arguments and returns ModuleRequest RecordList. 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 mr,执行
    1. 如果 requests 不包含一个 ModuleRequest Record mr2,使得 ModuleRequestsEqual(mr, mr2) 为 true,则
      1. mr 追加到 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. attributesWithClauseWithClauseToAttributes
  3. 返回一个 List,其唯一元素为 ModuleRequest Record { [[Specifier]]: specifier, [[Attributes]]: attributes }。
ImportDeclaration : import ModuleSpecifier ;
  1. specifierModuleSpecifierSV
  2. 返回一个 List,其唯一元素为 ModuleRequest Record { [[Specifier]]: specifier, [[Attributes]]: « » }。
ImportDeclaration : import ModuleSpecifier WithClause ;
  1. specifierModuleSpecifierSV
  2. attributesWithClauseWithClauseToAttributes
  3. 返回一个 List,其唯一元素为 ModuleRequest Record { [[Specifier]]: specifier, [[Attributes]]: attributes }。
ExportDeclaration : export ExportFromClause FromClause ;
  1. specifierFromClauseSV
  2. 返回一个 List,其唯一元素为 ModuleRequest Record { [[Specifier]]: specifier, [[Attributes]]: « » }。
ExportDeclaration : export ExportFromClause FromClause WithClause ;
  1. specifierFromClauseSV
  2. attributesWithClauseWithClauseToAttributes
  3. 返回一个 List,其唯一元素为 ModuleRequest Record { [[Specifier]]: specifier, [[Attributes]]: attributes }。
ExportDeclaration : export NamedExports ; export VariableStatement export Declaration export default HoistableDeclaration export default ClassDeclaration export default AssignmentExpression ;
  1. 返回一个新的空 List

16.2.1.5 抽象模块记录

模块记录 封装了关于单个模块导入和导出的结构信息。 这些信息用于链接一组关联模块的导入与导出。 模块记录包含四个仅在评估模块时使用的字段。

从规范角度看,模块记录的值是 Record 规范类型的值, 可以认为处于一个简单的面向对象的类层次中, 其中模块记录是一个抽象类,拥有抽象子类和具体子类。 本规范定义了一个名为循环模块记录的抽象子类, 以及其具体子类源文本模块记录。 其他规范和实现可以定义额外的模块记录子类, 对应于它们定义的其他模块定义机制。

模块记录定义了 Table 38 中列出的字段。 所有模块定义的子类至少都包含这些字段。 模块记录还定义了 Table 39 中的抽象方法列表。 所有模块定义子类必须为这些抽象方法提供具体实现。

Table 38: 模块记录字段
字段名 值类型 含义
[[Realm]] 一个 Realm 记录 创建此模块的 Realm
[[Environment]] 一个模块环境记录或 empty 包含该模块顶层绑定的环境记录。此字段在模块被链接时设置。
[[Namespace]] 一个对象或 empty 如果已为该模块创建了模块命名空间对象(28.3),则为该对象。
[[HostDefined]] 任意值(默认值为 undefined 保留给需要将附加信息与模块关联的宿主环境使用的字段。
Table 39: Abstract Methods of Module Records
方法 目的 定义
LoadRequestedModules ( [ hostDefined ] )

The abstract method LoadRequestedModules takes optional argument hostDefined (任意值) and returns 一个 Promise.

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

在本规范内,此方法在以下类型中有定义;宿主可提供带有自定义定义的其他类型:
GetExportedNames ( [ exportStarSet ] )

The abstract method GetExportedNames takes optional argument exportStarSet (源文本模块记录的列表) and returns 字符串列表.

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

在调用本方法前,必须已经调用并成功完成 LoadRequestedModules

在本规范内,此方法在以下类型中有定义;宿主可提供带有自定义定义的其他类型:
ResolveExport ( exportName [ , resolveSet ] )

The abstract method ResolveExport takes argument exportName (字符串) and optional argument resolveSet (具有字段 [[Module]]模块记录)和 [[ExportName]](字符串)的记录列表) and returns ResolvedBinding 记录nullambiguous.

返回该模块导出的某个名称的绑定。绑定由 ResolvedBinding 记录 表示, 形式为 { [[Module]]: 模块记录, [[BindingName]]: 字符串 | namespace }。 如果导出是没有任何模块直接绑定的模块命名空间对象,[[BindingName]]namespace。 如果名称无法解析,返回 null;如发现多个绑定,返回 ambiguous

每次使用特定 exportNameresolveSet 调用本操作时,必须返回相同结果。

在调用本方法前,必须已成功完成 LoadRequestedModules

在本规范内,此方法在以下类型中有定义;宿主可提供带有自定义定义的其他类型:
Evaluate ( )

The abstract method Evaluate takes no arguments and returns 一个 Promise.

返回一个 promise,其结果为评估该模块及其依赖的过程。 若评估成功或已经成功则 resolve,若失败或之前已失败则 reject。 若 promise 被拒绝,宿主应处理 promise 拒绝并重新抛出评估错误。 除非该模块是循环模块记录,否则返回的 promise 必须已结算。

在调用本方法前,必须已成功完成 Link

在本规范内,此方法在以下类型中有定义;宿主可提供带有自定义定义的其他类型:

16.2.1.5.1 EvaluateModuleSync ( module )

The abstract operation EvaluateModuleSync takes argument module (一个模块记录) and returns 返回包含 unused正常完成或 throw completion. 同步地对 module 求值,前提是调用方保证 module 的求值将返回一个已经 settled 的 promise。 It performs the following steps when called:

  1. 断言:module 不是循环模块记录
  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 循环模块记录

循环模块记录用于表示可以与其他循环模块记录类型的子类模块参与依赖循环的模块信息。不属于循环模块记录类型子类的模块记录不得与源文本模块记录参与依赖循环。

除了在Table 38中定义的字段外,循环模块记录还具有在Table 40中列出的附加字段

Table 40: 循环模块记录的附加字段
字段名 值类型 含义
[[Status]] newunlinkedlinkinglinkedevaluatingevaluating-asyncevaluated 初始为 new。随着模块在其生命周期中的推进,依次转换为 unlinkedlinkinglinkedevaluating,可能为 evaluating-async,最终为 evaluatedevaluating-async 表示该模块被排队等待其异步依赖完成后执行,或该模块的 [[HasTLA]] 字段为 true 且已执行并等待顶层完成。
[[EvaluationError]] 一个 throw completion 或 empty 表示在求值过程中发生的异常的 throw completion。如果未发生异常或 [[Status]] 不是 evaluated,则为 empty
[[DFSAncestorIndex]] 一个整数empty 仅在 LinkEvaluate 期间使用的辅助字段。如果 [[Status]]linkingevaluating,该值为模块的深度优先遍历索引,或同一强连通分量中“更早”的模块的索引。
[[RequestedModules]] ModuleRequest Record 的列表 与该模块中 import 相关联的 ModuleRequest Record 列表。该列表按源代码中 import 出现的顺序排列。
[[LoadedModules]] LoadedModuleRequest Record 的列表 一个从该模块使用的说明符字符串(用于请求导入模块,并带有相对导入属性)映射到已解析的模块记录的映射。该列表中不存在两个不同记录 r1r2 使得 ModuleRequestsEqual(r1, r2) 为 true
[[CycleRoot]] 一个循环模块记录empty 循环中首次访问的模块,即该强连通分量的 DFS 根祖先。对于不在循环中的模块,该值为模块自身。在 Evaluate 完成后,模块的 [[DFSAncestorIndex]] 是其 [[CycleRoot]] 的深度优先遍历索引。
[[HasTLA]] 一个布尔值 指示该模块是否本身是异步的(例如,包含顶层 await 的源文本模块记录)。拥有异步依赖并不意味着该字段为 true。该字段在模块解析后不得更改。
[[AsyncEvaluationOrder]] unset、一个整数done 该字段初始为 unset,对于完全同步的模块保持为 unset。对于自身为异步或具有异步依赖的模块,该字段被设置为一个整数,用于确定在16.2.1.6.1.3.4中排队执行待处理模块的顺序。一旦模块成功执行,该字段设置为 done
[[TopLevelCapability]] 一个 PromiseCapability Recordempty 如果该模块是某个循环的 [[CycleRoot]],且对该循环中的某个模块调用了 Evaluate(),则该字段包含整个求值过程的 PromiseCapability Record。它用于兑现 Evaluate() 抽象方法返回的 Promise 对象。对于该模块的依赖,该字段为 empty,除非对这些依赖中的某些模块启动了顶层 Evaluate()。
[[AsyncParentModules]] 循环模块记录的列表 如果该模块或其依赖的 [[HasTLA]]true,且执行正在进行中,则该字段跟踪该模块在顶层执行任务中的父导入模块。这些父模块在该模块成功完成执行之前不会开始执行。
[[PendingAsyncDependencies]] 一个整数empty 如果该模块具有异步依赖,该字段用于跟踪该模块剩余待执行的异步依赖模块数量。当该字段为 0 且没有执行错误时,该模块将被执行。

除了在Table 39中定义的方法外,循环模块记录还具有在Table 41中列出的附加方法:

Table 41: 循环模块记录的附加抽象方法
方法 目的 定义
InitializeEnvironment ( )

The abstract method InitializeEnvironment takes no arguments and returns 返回包含 unused正常完成或 throw completion.

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

The abstract method ExecuteModule takes optional argument capability (一个 PromiseCapability Record,) and returns 返回包含 unused正常完成或 throw completion.

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

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

Table 42: GraphLoadingState 记录字段
字段名 值类型 含义
[[PromiseCapability]] 一个 PromiseCapability Record 在加载过程完成时需要解析的 promise。
[[IsLoading]] 一个布尔值 如果加载过程尚未结束(既未成功也未出错),则为 true。
[[PendingModulesCount]] 一个非负整数 用于跟踪待处理的 HostLoadImportedModule 调用数量。
[[Visited]] 循环模块记录的列表 当前加载过程中已经加载的循环模块记录列表,用于避免循环依赖导致的无限循环。
[[HostDefined]] 任意值(默认值为 empty 包含由宿主定义的数据,用于从 LoadRequestedModules 调用方传递到 HostLoadImportedModule

16.2.1.6.1 模块记录抽象方法的实现

以下是循环模块记录的具体方法,用于实现Table 39中定义的对应模块记录抽象方法。

16.2.1.6.1.1 LoadRequestedModules ( [ hostDefined ] )

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

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

16.2.1.6.1.1.1 InnerModuleLoading ( state, module )

The abstract operation InnerModuleLoading takes arguments state (一个 GraphLoadingState 记录) and module (一个模块记录) and returns unused. 被 LoadRequestedModules 使用,用于递归执行 module 依赖图的实际加载过程。 It performs the following steps when called:

  1. 断言:state.[[IsLoading]]true
  2. 如果 module循环模块记录,且 module.[[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]] 中的每个循环模块记录 loaded,执行
      1. 如果 loaded.[[Status]]new,则将其设为 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 (一个 GraphLoadingState 记录) and moduleCompletion (一个包含模块记录正常完成或 throw completion) and returns unused. 用于在调用 HostLoadImportedModule 之后重新进入加载过程。 It performs the following steps when called:

  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 ( )

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

  1. 断言:module.[[Status]]unlinkedlinkedevaluating-asyncevaluated 之一。
  2. stack 为一个新的空列表。
  3. resultCompletion(InnerModuleLinking(module, stack, 0))。
  4. 如果 result 是异常完成,则
    1. 对于 stack 中的每个循环模块记录 m,执行
      1. 断言:m.[[Status]]linking
      2. m.[[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 (一个模块记录), stack (循环模块记录的列表), and index (一个非负整数) and returns 返回包含一个非负整数正常完成或 throw completion. 被 Link 使用,用于执行 module 的实际链接过程,并递归处理依赖图中的所有其他模块。stackindex 参数,以及模块的 [[DFSAncestorIndex]] 字段,用于跟踪深度优先搜索(DFS)遍历。特别是,[[DFSAncestorIndex]] 用于发现强连通分量(SCC),使得同一 SCC 中的所有模块一起转换为 linked。 It performs the following steps when called:

  1. 如果 module 不是循环模块记录,则
    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. 如果 requiredModule循环模块记录,则
      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. 重复执行,直到 donetrue
      1. requiredModulestack 的最后一个元素。
      2. stack 中移除最后一个元素。
      3. 断言:requiredModule循环模块记录
      4. requiredModule.[[Status]] 设为 linked
      5. 如果 requiredModulemodule 是同一个模块记录,则将 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 一个 Promise. Evaluate 将该模块的 [[Status]]linked 转换为 evaluating-asyncevaluated。在某个强连通分量中第一次调用时,Evaluate 会创建并返回一个 Promise,该 Promise 在模块完成求值时被解析。该 Promise 存储在该分量的 [[CycleRoot]][[TopLevelCapability]] 字段中。之后在该分量中任意模块上调用 Evaluate 都会返回同一个 Promise。(大部分工作由辅助函数 InnerModuleEvaluation 完成。) It performs the following steps when called:

  1. 断言:在同一代理中,对 Evaluate 的此调用不会与另一个 Evaluate 调用同时发生。
  2. 断言:module.[[Status]]linkedevaluating-asyncevaluated 之一。
  3. 如果 module.[[Status]]evaluating-asyncevaluated,则
    1. 如果 module.[[CycleRoot]] 不为 empty,则
      1. module 设为 module.[[CycleRoot]]
    2. 否则,
      1. 断言:module.[[Status]]evaluatedmodule.[[EvaluationError]] 为 throw completion。
  4. 如果 module.[[TopLevelCapability]] 不为 empty,则
    1. 返回 module.[[TopLevelCapability]].[[Promise]]
  5. stack 为一个新的空列表。
  6. capability 为 ! NewPromiseCapability(%Promise%)。
  7. module.[[TopLevelCapability]] 设为 capability
  8. resultCompletion(InnerModuleEvaluation(module, stack, 0))。
  9. 如果 result 是异常完成,则
    1. 对于 stack 中的每个循环模块记录 m,执行
      1. 断言:m.[[Status]]evaluating
      2. m.[[Status]] 设为 evaluated
      3. m.[[EvaluationError]] 设为 result
    2. 断言:module.[[Status]]evaluated
    3. 断言:module.[[EvaluationError]]result 是同一个 Completion Record
    4. 执行 ! Call(capability.[[Reject]], undefined, « result.[[Value]] »)。
  10. 否则,
    1. 断言:module.[[Status]]evaluating-asyncevaluated
    2. 断言:module.[[EvaluationError]]empty
    3. 如果 module.[[Status]]evaluated,则
      1. 断言:module.[[AsyncEvaluationOrder]]unsetdone
      2. 注意:当且仅当该模块之前已经被异步求值时,module.[[AsyncEvaluationOrder]]done
      3. 执行 ! Call(capability.[[Resolve]], undefined, « undefined »)。
    4. 断言:stack 为空。
  11. 返回 capability.[[Promise]]

16.2.1.6.1.3.1 InnerModuleEvaluation ( module, stack, index )

The abstract operation InnerModuleEvaluation takes arguments module (一个模块记录), stack (循环模块记录的列表), and index (一个非负整数) and returns 返回包含一个非负整数正常完成或 throw completion. 被 Evaluate 使用,用于执行 module 的实际求值过程,并递归处理依赖图中的所有其他模块。stackindex 参数,以及 module[[DFSAncestorIndex]] 字段,与 InnerModuleLinking 中的使用方式相同。 It performs the following steps when called:

  1. 如果 module 不是循环模块记录,则
    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. 如果 requiredModule循环模块记录,则
      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. 重复执行,直到 donetrue
      1. requiredModulestack 的最后一个元素。
      2. stack 中移除最后一个元素。
      3. 断言:requiredModule循环模块记录
      4. 断言:requiredModule.[[AsyncEvaluationOrder]]整数unset
      5. 如果 requiredModule.[[AsyncEvaluationOrder]]unset,则将 requiredModule.[[Status]] 设为 evaluated
      6. 否则,将 requiredModule.[[Status]] 设为 evaluating-async
      7. 如果 requiredModulemodule 是同一个模块记录,则将 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 (一个循环模块记录) and returns unused. It performs the following steps when called:

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

16.2.1.6.1.3.3 GatherAvailableAncestors ( module, execList )

The abstract operation GatherAvailableAncestors takes arguments module (一个循环模块记录) and execList (循环模块记录的列表) and returns unused. It performs the following steps when called:

  1. 对于 module.[[AsyncParentModules]] 中的每个循环模块记录 m,执行
    1. 如果 execList 不包含 mm.[[CycleRoot]].[[EvaluationError]]empty,则
      1. 断言:m.[[Status]]evaluating-async
      2. 断言:m.[[EvaluationError]]empty
      3. 断言:m.[[AsyncEvaluationOrder]]整数
      4. 断言:m.[[PendingAsyncDependencies]] > 0。
      5. m.[[PendingAsyncDependencies]] 设为 m.[[PendingAsyncDependencies]] - 1。
      6. 如果 m.[[PendingAsyncDependencies]] = 0,则
        1. m 追加到 execList
        2. 如果 m.[[HasTLA]]false,则执行 GatherAvailableAncestors(m, execList)。
  2. 返回 unused
Note

当某个根模块 module 的异步执行完成时,此函数用于确定可以在该完成点同步执行的一组模块,并将它们填充到 execList 中。

16.2.1.6.1.3.4 AsyncModuleExecutionFulfilled ( module )

The abstract operation AsyncModuleExecutionFulfilled takes argument module (一个循环模块记录) 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 是同一个模块记录
    2. 执行 ! Call(module.[[TopLevelCapability]].[[Resolve]], undefined, « undefined »)。
  8. execList 为一个新的空列表。
  9. 执行 GatherAvailableAncestors(module, execList)。
  10. 断言:execList 中所有元素的 [[AsyncEvaluationOrder]] 字段为整数[[PendingAsyncDependencies]] 字段为 0,且 [[EvaluationError]] 字段为 empty
  11. sortedExecList 为一个列表,其元素为 execList 的元素,并按其 [[AsyncEvaluationOrder]] 字段升序排序。
  12. 对于 sortedExecList 中的每个循环模块记录 m,执行
    1. 如果 m.[[Status]]evaluated,则
      1. 断言:m.[[EvaluationError]] 不为 empty
    2. 否则如果 m.[[HasTLA]]true,则
      1. 执行 ExecuteAsyncModule(m)。
    3. 否则,
      1. resultCompletion(m.ExecuteModule())。
      2. 如果 result 是异常完成,则
        1. 执行 AsyncModuleExecutionRejected(m, result.[[Value]])。
      3. 否则,
        1. m.[[AsyncEvaluationOrder]] 设为 done
        2. m.[[Status]] 设为 evaluated
        3. 如果 m.[[TopLevelCapability]] 不为 empty,则
          1. 断言:m.[[CycleRoot]]m 是同一个模块记录
          2. 执行 ! Call(m.[[TopLevelCapability]].[[Resolve]], undefined, « undefined »)。
  13. 返回 unused

16.2.1.6.1.3.5 AsyncModuleExecutionRejected ( module, error )

The abstract operation AsyncModuleExecutionRejected takes arguments module (一个循环模块记录) and error (一个 ECMAScript 语言值) 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. 注意:为了与 AsyncModuleExecutionFulfilled 对称,module.[[AsyncEvaluationOrder]] 被设为 done。在 InnerModuleEvaluation 中,当模块的 [[EvaluationError]] 不为 empty 时,其 [[AsyncEvaluationOrder]] 内部槽的值不会被使用。
  9. 如果 module.[[TopLevelCapability]] 不为 empty,则
    1. 断言:module.[[CycleRoot]]module 是同一个模块记录
    2. 执行 ! Call(module.[[TopLevelCapability]].[[Reject]], undefined, « error »)。
  10. 对于 module.[[AsyncParentModules]] 中的每个循环模块记录 m,执行
    1. 执行 AsyncModuleExecutionRejected(m, error)。
  11. 返回 unused

16.2.1.6.2 循环模块记录图示例

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

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

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(),该调用会成功完成,返回一个解析为 undefined 的 Promise(同样根据假设),并且递归地先对 C 求值,再对 B 求值。此时每个模块的 [[Status]] 都将为 evaluated

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

最后,考虑在成功调用 Link() 之后涉及求值错误的情况。如果 CInnerModuleEvaluation 成功,但随后 B 失败,例如因为 B 包含会抛出异常的代码,那么原始的 A.Evaluate() 将失败,返回一个 rejected Promise。产生的异常会记录在 AB[[EvaluationError]] 字段中,并且它们的 [[Status]] 将变为 evaluatedC 也会变为 evaluated,但与 AB 不同,它不会有 [[EvaluationError]],因为它已成功完成求值。存储该异常可确保宿主日后任何时候尝试通过调用 ABEvaluate() 方法来复用它们时,都会遇到同一个异常。(宿主不要求复用循环模块记录;类似地,宿主也不要求暴露这些方法抛出的异常对象。不过,本规范允许此类用途。)

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

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

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

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

  • 求值必须只执行一次,因为它可能产生副作用;因此,即使求值未成功,记住求值是否已经执行过也很重要。(在错误情况下,也有必要记住异常,否则后续 Evaluate() 调用将不得不合成一个新的异常。)
  • 另一方面,链接没有副作用,因此即使链接失败,也可以在之后无问题地重试。
  • 加载与宿主紧密交互,对某些宿主而言,允许用户重试失败的加载可能是可取的(例如,当失败由暂时不佳的网络条件导致时)。

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

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

这里我们假设入口点是模块 A,因此宿主通过调用 A.LoadRequestedModules() 开始,它会在 A 上执行 InnerModuleLoading。这又会在 BC 上调用 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 之后,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 的模块形成一条贯穿整个依赖图的链,并通过 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,由于它已经是 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。此时,各模块的字段如Table 43所示。

Table 43: 初始 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 44所示。

Table 44: 模块 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),因此会先处理 BB.[[PendingAsyncDependencies]] 递减为 0,在 B 上调用 ExecuteAsyncModule,并开始执行。C.[[PendingAsyncDependencies]] 也递减为 0,C 开始执行(如果 B 包含 await,则可能与 B 并行执行)。更新后的模块字段如Table 45所示。

Table 45: 模块 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 46所示。

Table 46: 模块 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 47所示。

Table 47: 模块 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() 返回的 Promise)被解析,这就完成了此模块图的处理。更新后的模块字段如Table 48所示。

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

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

Table 49: 模块 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 上调用 AsyncModuleExecutionRejectedA.[[Status]] 被设置为 evaluated。此时,A.[[TopLevelCapability]] 中的 Promise(即从 A.Evaluate() 返回的 Promise)被拒绝。更新后的模块字段如Table 50所示。

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

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

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

16.2.1.7 源文本模块记录

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

源文本模块记录可以与抽象模块记录类型的其他子类共存于一个模块图中,并且可以与循环模块记录类型的其他子类参与循环。

除了在Table 40中定义的字段外,源文本模块记录还具有在Table 52中列出的附加字段。这些字段中的每一个最初都在 ParseModule 中设置。

Table 52: 源文本模块记录的附加字段
字段名 值类型 含义
[[ECMAScriptCode]] 一个解析节点 使用 Module 作为目标符号解析该模块源文本的结果。
[[Context]] 一个 ECMAScript 代码执行上下文empty 与该模块关联的执行上下文。在模块的环境被初始化之前,它为 empty
[[ImportMeta]] 一个对象或 empty 通过 import.meta 元属性暴露的对象。在 ECMAScript 代码访问它之前,它为 empty
[[ImportEntries]] ImportEntry 记录的列表 从该模块代码派生出的 ImportEntry 记录列表。
[[LocalExportEntries]] ExportEntry 记录的列表 从该模块代码派生出的 ExportEntry 记录列表,对应于模块内部出现的声明。
[[IndirectExportEntries]] ExportEntry 记录的列表 从该模块代码派生出的 ExportEntry 记录列表,对应于模块内部出现的重导出导入,或来自 export * as namespace 声明的导出。
[[StarExportEntries]] ExportEntry 记录的列表 从该模块代码派生出的 ExportEntry 记录列表,对应于模块内部出现的 export * 声明,不包括 export * as namespace 声明。

ImportEntry 记录是一个记录,用于摘要关于单个声明式导入的信息。每个 ImportEntry 记录具有在Table 53中定义的字段:

Table 53: ImportEntry 记录字段
字段名 值类型 含义
[[ModuleRequest]] 一个 ModuleRequest 记录 表示 ImportDeclarationModuleSpecifier 和导入属性的 ModuleRequest 记录。
[[ImportName]] 一个字符串或 namespace [[ModuleRequest]] 标识的模块导出所需绑定所使用的名称。值 namespace 表示导入请求针对目标模块的命名空间对象。
[[LocalName]] 一个字符串 在导入模块内部用于本地访问导入值的名称。
Note 1

Table 54给出了用于表示语法导入形式的 ImportEntry 记录字段示例:

Table 54 (Informative): 导入形式到 ImportEntry 记录的映射
导入语句形式 [[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 记录

ExportEntry 记录是一个记录,用于摘要关于单个声明式导出的信息。每个 ExportEntry 记录具有在Table 55中定义的字段:

Table 55: ExportEntry 记录字段
字段名 值类型 含义
[[ExportName]] 一个字符串或 null 此模块用于导出该绑定的名称。
[[ModuleRequest]] 一个 ModuleRequest 记录或 null 表示 ExportDeclarationModuleSpecifier 和导入属性的 ModuleRequest 记录。如果 ExportDeclaration 没有 ModuleSpecifier,则为 null
[[ImportName]] 一个字符串、nullnamespaceall-but-default [[ModuleRequest]] 标识的模块导出所需绑定所使用的名称。如果 ExportDeclaration 没有 ModuleSpecifier,则为 nullnamespace 用于 export * as ns from "mod" 声明。all-but-default 用于 export * from "mod" 声明。
[[LocalName]] 一个字符串或 null 在导入模块内部用于本地访问导出值的名称。如果导出的值在模块内部无法本地访问,则为 null
Note 2

Table 56给出了用于表示语法导出形式的 ExportEntry 记录字段示例:

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

以下定义指定源文本模块记录所需的具体方法和其他抽象操作

16.2.1.7.1 ParseModule ( sourceText, realm, hostDefined )

The abstract operation ParseModule takes arguments sourceText (ECMAScript 源文本), realm (一个 Realm 记录), and hostDefined (任意值) and returns 一个源文本模块记录或一个非空 SyntaxError 对象列表. 基于将 sourceText 解析为 Module 的结果创建一个源文本模块记录。 It performs the following steps when called:

  1. bodyParseText(sourceText, Module)。
  2. 如果 body 是错误列表,则返回 body
  3. requestedModulesbodyModuleRequests
  4. importEntriesbodyImportEntries
  5. importedBoundNamesImportedLocalNames(importEntries)。
  6. indirectExportEntries 为一个新的空列表。
  7. localExportEntries 为一个新的空列表。
  8. starExportEntries 为一个新的空列表。
  9. exportEntriesbodyExportEntries
  10. 对于 exportEntries 中的每个 ExportEntry 记录 ee,执行
    1. 如果 ee.[[ModuleRequest]]null,则
      1. 如果 importedBoundNames 不包含 ee.[[LocalName]],则
        1. ee 追加到 localExportEntries
      2. 否则,
        1. 注意:当导出最初从另一个模块导入的绑定或命名空间对象时,ExportEntry 记录会被重写为与该绑定或命名空间对象直接从原始模块重导出时所具有的形式相匹配,而不是先导入再导出。这允许通过 export * from 以相同名称导出同一绑定或命名空间两次所产生的冲突被忽略,而不是在源文本模块记录的 ResolveExport 具体方法的步骤9.e.iii中被视为歧义。
        2. ieimportEntries[[LocalName]]ee.[[LocalName]] 的元素。
        3. ExportEntry 记录 { [[ModuleRequest]]: ie.[[ModuleRequest]], [[ImportName]]: ie.[[ImportName]], [[LocalName]]: null, [[ExportName]]: ee.[[ExportName]] } 追加到 indirectExportEntries
    2. 否则如果 ee.[[ImportName]]all-but-default,则
      1. 断言:ee.[[ExportName]]null
      2. ee 追加到 starExportEntries
    3. 否则,
      1. ee 追加到 indirectExportEntries
  11. asyncbody Contains await
  12. 返回源文本模块记录 { [[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 之前解析模块源文本并分析其 Early Error 条件。然而,任何错误的报告都必须推迟到本规范实际对该源文本执行 ParseModule 的时刻。

16.2.1.7.2 模块记录抽象方法的实现

以下是源文本模块记录的具体方法,用于实现Table 39中定义的对应模块记录抽象方法。

16.2.1.7.2.1 GetExportedNames ( [ exportStarSet ] )

The GetExportedNames concrete method of a Source Text Module Record module takes optional argument exportStarSet (源文本模块记录的列表) and returns 字符串列表. It performs the following steps when called:

  1. 断言:module.[[Status]] 不是 new
  2. 如果 exportStarSet 未提供,则将 exportStarSet 设为一个新的空列表。
  3. 如果 exportStarSet 包含 module,则
    1. 断言:我们已经到达 export * 循环的起点。
    2. 返回一个新的空列表。
  4. module 追加到 exportStarSet
  5. exportedNames 为一个新的空列表。
  6. 对于 module.[[LocalExportEntries]] 中的每个 ExportEntry 记录 e,执行
    1. 断言:module 为此导出提供直接绑定。
    2. 断言:e.[[ExportName]] 不是 null
    3. e.[[ExportName]] 追加到 exportedNames
  7. 对于 module.[[IndirectExportEntries]] 中的每个 ExportEntry 记录 e,执行
    1. 断言:module 为此导出导入一个特定绑定。
    2. 断言:e.[[ExportName]] 不是 null
    3. e.[[ExportName]] 追加到 exportedNames
  8. 对于 module.[[StarExportEntries]] 中的每个 ExportEntry 记录 e,执行
    1. 断言:e.[[ModuleRequest]] 不是 null
    2. requestedModuleGetImportedModule(module, e.[[ModuleRequest]])。
    3. starNamesrequestedModule.GetExportedNames(exportStarSet)。
    4. 对于 starNames 中的每个元素 n,执行
      1. 如果 n 不是 "default",则
        1. 如果 exportedNames 不包含 n,则
          1. n 追加到 exportedNames
  9. 返回 exportedNames
Note

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

16.2.1.7.2.2 ResolveExport ( exportName [ , resolveSet ] )

The ResolveExport concrete method of a Source Text Module Record module takes argument exportName (一个字符串) and optional argument resolveSet (具有字段 [[Module]](一个模块记录)和 [[ExportName]](一个字符串)的记录列表) and returns 一个 ResolvedBinding 记录nullambiguous.

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

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

It performs the following steps when called:

  1. 断言:module.[[Status]] 不是 new
  2. 如果 resolveSet 未提供,则将 resolveSet 设为一个新的空列表。
  3. 对于 resolveSet 中的每个记录 { [[Module]], [[ExportName]] } r,执行
    1. 如果 moduler.[[Module]] 是同一个模块记录,且 exportNamer.[[ExportName]],则
      1. 断言:这是一个循环导入请求。
      2. 返回 null
  4. 将记录 { [[Module]]: module, [[ExportName]]: exportName } 追加到 resolveSet
  5. 对于 module.[[LocalExportEntries]] 中的每个 ExportEntry 记录 e,执行
    1. 如果 e.[[ExportName]]exportName,则
      1. 断言:module 为此导出提供直接绑定。
      2. 返回 ResolvedBinding 记录 { [[Module]]: module, [[BindingName]]: e.[[LocalName]] }。
  6. 对于 module.[[IndirectExportEntries]] 中的每个 ExportEntry 记录 e,执行
    1. 如果 e.[[ExportName]]exportName,则
      1. 断言:e.[[ModuleRequest]] 不是 null
      2. importedModuleGetImportedModule(module, e.[[ModuleRequest]])。
      3. 如果 e.[[ImportName]]namespace,则
        1. 断言:module 不为此导出提供直接绑定。
        2. 返回 ResolvedBinding 记录 { [[Module]]: importedModule, [[BindingName]]: namespace }。
      4. 断言:module 为此导出导入一个特定绑定。
      5. 断言:e.[[ImportName]] 是一个字符串。
      6. 返回 importedModule.ResolveExport(e.[[ImportName]], resolveSet)。
  7. 如果 exportName"default",则
    1. 断言:此模块未显式定义 default 导出。
    2. 返回 null
    3. 注意:default 导出不能由 export * from "mod" 声明提供。
  8. starResolutionnull
  9. 对于 module.[[StarExportEntries]] 中的每个 ExportEntry 记录 e,执行
    1. 断言:e.[[ModuleRequest]] 不是 null
    2. importedModuleGetImportedModule(module, e.[[ModuleRequest]])。
    3. resolutionimportedModule.ResolveExport(exportName, resolveSet)。
    4. 如果 resolutionambiguous,返回 ambiguous
    5. 如果 resolution 不是 null,则
      1. 断言:resolution 是一个 ResolvedBinding 记录
      2. 如果 starResolutionnull,则
        1. starResolution 设为 resolution
      3. 否则,
        1. 断言:存在多个包含所请求名称的 * 导出。
        2. 如果 resolution.[[Module]]starResolution.[[Module]] 不是同一个模块记录,返回 ambiguous
        3. 如果 resolution.[[BindingName]] 不是 starResolution.[[BindingName]],返回 ambiguous
  10. 返回 starResolution

16.2.1.7.3 循环模块记录抽象方法的实现

以下是源文本模块记录的具体方法,用于实现Table 41中定义的对应循环模块记录抽象方法。

16.2.1.7.3.1 InitializeEnvironment ( )

The InitializeEnvironment concrete method of a Source Text Module Record module takes no arguments and returns 返回包含 unused正常完成或 throw completion. It performs the following steps when called:

  1. 对于 module.[[IndirectExportEntries]] 中的每个 ExportEntry 记录 e,执行
    1. 断言:e.[[ExportName]] 不是 null
    2. resolutionmodule.ResolveExport(e.[[ExportName]])。
    3. 如果 resolutionnullambiguous,则抛出一个 SyntaxError 异常。
    4. 断言:resolution 是一个 ResolvedBinding 记录
  2. 断言:来自 module 的所有命名导出都是可解析的。
  3. realmmodule.[[Realm]]
  4. 断言:realm 不是 undefined
  5. envNewModuleEnvironment(realm.[[GlobalEnv]])。
  6. module.[[Environment]] 设为 env
  7. 对于 module.[[ImportEntries]] 中的每个 ImportEntry 记录 in,执行
    1. importedModuleGetImportedModule(module, in.[[ModuleRequest]])。
    2. 如果 in.[[ImportName]]namespace,则
      1. namespaceGetModuleNamespace(importedModule)。
      2. 执行 ! env.CreateImmutableBinding(in.[[LocalName]], true)。
      3. 执行 ! env.InitializeBinding(in.[[LocalName]], namespace)。
    3. 否则,
      1. 断言:in.[[ImportName]] 是一个字符串。
      2. resolutionimportedModule.ResolveExport(in.[[ImportName]])。
      3. 如果 resolutionnullambiguous,则抛出一个 SyntaxError 异常。
      4. 如果 resolution.[[BindingName]]namespace,则
        1. namespaceGetModuleNamespace(resolution.[[Module]])。
        2. 执行 ! env.CreateImmutableBinding(in.[[LocalName]], true)。
        3. 执行 ! env.InitializeBinding(in.[[LocalName]], namespace)。
      5. 否则,
        1. 执行 CreateImportBinding(env, in.[[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. varDeclarationscodeVarScopedDeclarations
  20. declaredVarNames 为一个新的空列表。
  21. 对于 varDeclarations 中的每个元素 d,执行
    1. 对于 dBoundNames 中的每个元素 dn,执行
      1. 如果 declaredVarNames 不包含 dn,则
        1. 执行 ! env.CreateMutableBinding(dn, false)。
        2. 执行 ! env.InitializeBinding(dn, undefined)。
        3. dn 追加到 declaredVarNames
  22. lexDeclarationscodeLexicallyScopedDeclarations
  23. privateEnvnull
  24. 对于 lexDeclarations 中的每个元素 d,执行
    1. 对于 dBoundNames 中的每个元素 dn,执行
      1. 如果 dIsConstantDeclarationtrue,则
        1. 执行 ! env.CreateImmutableBinding(dn, true)。
      2. 否则,
        1. 执行 ! env.CreateMutableBinding(dn, false)。
      3. 如果 dFunctionDeclarationGeneratorDeclarationAsyncFunctionDeclarationAsyncGeneratorDeclaration,则
        1. fo 为以 envprivateEnv 为参数对 d 执行 InstantiateFunctionObject 的结果。
        2. 执行 ! env.InitializeBinding(dn, fo)。
  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 (一个 PromiseCapability 记录) and returns 返回包含 unused正常完成或 throw completion. It performs the following steps when called:

  1. 断言:module 已被链接,且其模块环境中的声明已被实例化。
  2. moduleContextmodule.[[Context]]
  3. 如果 module.[[HasTLA]]false,则
    1. 断言:capability 未提供。
    2. 挂起运行中的执行上下文
    3. moduleContext 压入执行上下文栈moduleContext 现在是运行中的执行上下文
    4. resultCompletion(对 module.[[ECMAScriptCode]] 求值)。
    5. 挂起 moduleContext 并将其从执行上下文栈中移除。
    6. 恢复现在位于执行上下文栈顶部的上下文作为运行中的执行上下文
    7. 如果 result 是异常完成,则
      1. 返回 ? result
  4. 否则,
    1. 断言:capability 是一个 PromiseCapability 记录。
    2. 执行 AsyncBlockStart(capability, module.[[ECMAScriptCode]], moduleContext)。
  5. 返回 unused

16.2.1.8 合成模块记录

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

Note
合成模块记录可用于定义各种模块类型:例如 JSON 模块或 CSS 模块。

除了在Table 38中定义的字段外,合成模块记录还具有在Table 57中列出的附加字段。

Table 57: 合成模块记录的附加字段
字段名 值类型 含义
[[ExportNames]] 字符串列表 该模块的导出名称。此列表不包含重复项。
[[EvaluationSteps]] 一个抽象闭包 在模块求值时执行的初始化逻辑,以该合成模块记录作为其唯一参数。它不得修改 [[ExportNames]]。它可以返回一个异常完成。

16.2.1.8.1 CreateDefaultExportSyntheticModule ( defaultExport )

The abstract operation CreateDefaultExportSyntheticModule takes argument defaultExport (一个 ECMAScript 语言值) and returns 一个合成模块记录. 创建一个默认导出为 defaultExport合成模块记录。 It performs the following steps when called:

  1. realm 为当前 Realm 记录。
  2. setDefaultExport 为一个新的抽象闭包,其参数为 (module),捕获 defaultExport,并在调用时执行以下步骤:
    1. 执行 SetSyntheticModuleExport(module, "default", defaultExport)。
    2. 返回 NormalCompletion(unused)。
  3. 返回合成模块记录 { [[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 (一个字符串) and returns 返回包含合成模块记录正常完成,或 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 (一个合成模块记录), exportName (一个字符串), and exportValue (一个 ECMAScript 语言值) and returns unused. 可用于设置或更改合成模块记录现有导出的导出值。 It performs the following steps when called:

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

16.2.1.8.4 模块记录抽象方法的实现

以下是合成模块记录的具体方法,用于实现Table 39中定义的对应模块记录抽象方法。

16.2.1.8.4.1 LoadRequestedModules ( [ hostDefined ] )

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

  1. 注意:LoadRequestedModules 的此实现不使用 hostDefined
  2. 返回 ! PromiseResolve(%Promise%, undefined)。
Note
合成模块记录没有依赖。

16.2.1.8.4.2 GetExportedNames ( [ exportStarSet ] )

The GetExportedNames concrete method of a Synthetic Module Record module takes optional argument exportStarSet (源文本模块记录的列表) and returns 字符串列表. 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 (一个字符串) and optional argument resolveSet (具有字段 [[Module]](一个模块记录)和 [[ExportName]](一个字符串)的记录列表) and returns 一个 ResolvedBinding 记录nullambiguous. It performs the following steps when called:

  1. 注意:ResolveExport 的此实现不使用 resolveSet
  2. 如果 module.[[ExportNames]] 不包含 exportName,返回 null
  3. 返回 ResolvedBinding 记录 { [[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 包含 unused正常完成. It performs the following steps when called:

  1. realmmodule.[[Realm]]
  2. envNewModuleEnvironment(realm.[[GlobalEnv]])。
  3. module.[[Environment]] 设为 env
  4. 对于 module.[[ExportNames]] 中的每个字符串 exportName,执行
    1. 执行 ! env.CreateMutableBinding(exportName, false)。
    2. 执行 ! env.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 一个 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. pc 为 ! NewPromiseCapability(%Promise%)。
  14. IfAbruptRejectPromise(result, pc)。
  15. 执行 ! Call(pc.[[Resolve]], undefined, « undefined »)。
  16. 返回 pc.[[Promise]]

16.2.1.9 GetImportedModule ( referrer, request )

The abstract operation GetImportedModule takes arguments referrer (一个循环模块记录) and request (一个 ModuleRequest 记录) and returns 一个模块记录. It performs the following steps when called:

  1. records 为一个列表,由 referrer.[[LoadedModules]] 中满足 ModuleRequestsEqual(r, request) 为 true 的每个 LoadedModuleRequest 记录 r 组成。
  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 (一个 Script 记录、一个循环模块记录或一个 Realm 记录), moduleRequest (一个 ModuleRequest 记录), hostDefined (任意值), and payload (一个 GraphLoadingState 记录或一个 PromiseCapability 记录) and returns unused.

Note 1

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

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

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

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

实际执行的过程由宿主定义,但通常包括执行加载适当模块记录所需的任何 I/O 操作。多个不同的 (referrer, moduleRequest.[[Specifier]], moduleRequest.[[Attributes]]) 三元组可以映射到同一个模块记录实例。实际的映射语义由宿主定义,但通常会在映射过程中对 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 (一个 Script 记录、一个循环模块记录或一个 Realm 记录), moduleRequest (一个 ModuleRequest 记录), payload (一个 GraphLoadingState 记录或一个 PromiseCapability 记录), and result (包含模块记录正常完成或 throw completion) and returns unused. It performs the following steps when called:

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

16.2.1.12 AllImportAttributesSupported ( attributes )

The abstract operation AllImportAttributesSupported takes argument attributes (ImportAttribute 记录的列表) and returns 一个布尔值. It performs the following steps when called:

  1. supportedHostGetSupportedImportAttributes()。
  2. 对于 attributes 中的每个 ImportAttribute 记录 attribute,执行
    1. 如果 supported 不包含 attribute.[[Key]],返回 false
  3. 返回 true

16.2.1.12.1 HostGetSupportedImportAttributes ( )

The host-defined abstract operation HostGetSupportedImportAttributes takes no arguments and returns 字符串列表. 允许宿主环境指定它们支持哪些导入属性。只有具有受支持键的属性才会提供给宿主

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

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

HostGetSupportedImportAttributes 的默认实现是返回一个新的空列表。

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

16.2.1.13 GetModuleNamespace ( module )

The abstract operation GetModuleNamespace takes argument module (模块记录的某个具体子类实例) and returns 一个模块命名空间对象. 检索表示 module 导出的模块命名空间对象,在第一次请求时惰性创建它,并将其存储在 module.[[Namespace]] 中以便将来检索。 It performs the following steps when called:

  1. 断言:如果 module循环模块记录,则 module.[[Status]] 不是 newunlinked
  2. namespacemodule.[[Namespace]]
  3. 如果 namespaceempty,则
    1. exportedNamesmodule.GetExportedNames()。
    2. unambiguousNames 为一个新的空列表。
    3. 对于 exportedNames 中的每个元素 name,执行
      1. resolutionmodule.ResolveExport(name)。
      2. 如果 resolutionResolvedBinding 记录,则将 name 追加到 unambiguousNames
    4. namespace 设为 ModuleNamespaceCreate(module, unambiguousNames)。
  4. 返回 namespace
Note

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

16.2.1.14 Runtime Semantics: 求值

Module : [empty]
  1. 返回 undefined
ModuleBody : ModuleItemList
  1. resultCompletion(对 ModuleItemList 求值)。
  2. 如果 result正常完成result.[[Value]]empty,则
    1. 返回 undefined
  3. 返回 ? result
ModuleItemList : ModuleItemList ModuleItem
  1. sl 为 ? 对 ModuleItemList 求值。
  2. sCompletion(对 ModuleItem 求值)。
  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 ImportEntry 记录的列表. It is defined piecewise over the following productions:

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

16.2.2.3 Static Semantics: ImportEntriesForModule

The syntax-directed operation ImportEntriesForModule takes argument module (ModuleRequest 记录) and returns ImportEntry 记录的列表. 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 记录 { [[ModuleRequest]]: module, [[ImportName]]: "default", [[LocalName]]: localName }。
  3. 返回 « defaultEntry »。
NameSpaceImport : * as ImportedBinding
  1. localNameImportedBindingStringValue
  2. entryImportEntry 记录 { [[ModuleRequest]]: module, [[ImportName]]: namespace, [[LocalName]]: localName }。
  3. 返回 « entry »。
NamedImports : { }
  1. 返回一个新的空列表。
ImportsList : ImportsList , ImportSpecifier
  1. specs1 为以 module 为参数的 ImportsListImportEntriesForModule
  2. specs2 为以 module 为参数的 ImportSpecifierImportEntriesForModule
  3. 返回 specs1specs2 的列表拼接结果。
ImportSpecifier : ImportedBinding
  1. localNameImportedBindingBoundNames 的唯一元素。
  2. entryImportEntry 记录 { [[ModuleRequest]]: module, [[ImportName]]: localName, [[LocalName]]: localName }。
  3. 返回 « entry »。
ImportSpecifier : ModuleExportName as ImportedBinding
  1. importNameModuleExportNameStringValue
  2. localNameImportedBindingStringValue
  3. entryImportEntry 记录 { [[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 ImportAttribute 记录的列表. It is defined piecewise over the following productions:

WithClause : with { }
  1. 返回一个新的空列表。
WithClause : with { WithEntries ,opt }
  1. attributesWithEntriesWithClauseToAttributes
  2. 按照其 [[Key]] 字段的字典序对 attributes 排序,并将每个此类字段的值视为 UTF-16 代码单元值序列。注:这种排序唯一可观察之处在于,宿主被禁止基于属性枚举的顺序改变行为。
  3. 返回 attributes
WithEntries : AttributeKey : StringLiteral
  1. keyAttributeKeyPropName
  2. entry 为 ImportAttribute 记录 { [[Key]]: key, [[Value]]: StringLiteralSV }。
  3. 返回 « entry »。
WithEntries : AttributeKey : StringLiteral , WithEntries
  1. keyAttributeKeyPropName
  2. entry 为 ImportAttribute 记录 { [[Key]]: key, [[Value]]: StringLiteralSV }。
  3. restWithEntriesWithClauseToAttributes
  4. 返回 « entry » 和 rest 的列表拼接结果。

16.2.3 导出

语法

ExportDeclaration : export ExportFromClause FromClause WithClauseopt ; export NamedExports ; export VariableStatement[~Yield, +Await] export 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 字符串列表.

Note

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

It is defined piecewise over the following productions:

ModuleItemList : ModuleItemList ModuleItem
  1. names1ModuleItemListExportedBindings
  2. names2ModuleItemExportedBindings
  3. 返回 names1names2 的列表拼接结果。
ModuleItem : ImportDeclaration StatementListItem
  1. 返回一个新的空列表。
ExportDeclaration : export ExportFromClause FromClause WithClauseopt ;
  1. 返回一个新的空列表。
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. 返回一个新的空列表。
ExportsList : ExportsList , ExportSpecifier
  1. names1ExportsListExportedBindings
  2. names2ExportSpecifierExportedBindings
  3. 返回 names1names2 的列表拼接结果。
ExportSpecifier : ModuleExportName
  1. 返回一个列表,其唯一元素为 ModuleExportNameStringValue
ExportSpecifier : ModuleExportName as ModuleExportName
  1. 返回一个列表,其唯一元素为第一个 ModuleExportNameStringValue

16.2.3.3 Static Semantics: ExportedNames

The syntax-directed operation ExportedNames takes no arguments and returns 字符串列表.

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. 返回一个新的空列表。
ExportDeclaration : export ExportFromClause FromClause WithClauseopt ;
  1. 返回 ExportFromClauseExportedNames
ExportFromClause : *
  1. 返回一个新的空列表。
ExportFromClause : * as ModuleExportName
  1. 返回一个列表,其唯一元素为 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. 返回一个新的空列表。
ExportsList : ExportsList , ExportSpecifier
  1. names1ExportsListExportedNames
  2. names2ExportSpecifierExportedNames
  3. 返回 names1names2 的列表拼接结果。
ExportSpecifier : ModuleExportName
  1. 返回一个列表,其唯一元素为 ModuleExportNameStringValue
ExportSpecifier : ModuleExportName as ModuleExportName
  1. 返回一个列表,其唯一元素为第二个 ModuleExportNameStringValue

16.2.3.4 Static Semantics: ExportEntries

The syntax-directed operation ExportEntries takes no arguments and returns ExportEntry 记录的列表. It is defined piecewise over the following productions:

Module : [empty]
  1. 返回一个新的空列表。
ModuleItemList : ModuleItemList ModuleItem
  1. entries1ModuleItemListExportEntries
  2. entries2ModuleItemExportEntries
  3. 返回 entries1entries2 的列表拼接结果。
ModuleItem : ImportDeclaration StatementListItem
  1. 返回一个新的空列表。
ExportDeclaration : export ExportFromClause FromClause WithClauseopt ;
  1. moduleExportDeclarationModuleRequests 的唯一元素。
  2. 返回以 module 为参数的 ExportFromClauseExportEntriesForModule
ExportDeclaration : export NamedExports ;
  1. 返回以 null 为参数的 NamedExportsExportEntriesForModule
ExportDeclaration : export VariableStatement
  1. entries 为一个新的空列表。
  2. namesVariableStatementBoundNames
  3. names 的每个元素 name,执行
    1. ExportEntry 记录 { [[ModuleRequest]]: null, [[ImportName]]: null, [[LocalName]]: name, [[ExportName]]: name } 追加到 entries
  4. 返回 entries
ExportDeclaration : export Declaration
  1. entries 为一个新的空列表。
  2. namesDeclarationBoundNames
  3. names 的每个元素 name,执行
    1. ExportEntry 记录 { [[ModuleRequest]]: null, [[ImportName]]: null, [[LocalName]]: name, [[ExportName]]: name } 追加到 entries
  4. 返回 entries
ExportDeclaration : export default HoistableDeclaration
  1. namesHoistableDeclarationBoundNames
  2. localNamenames 的唯一元素。
  3. 返回一个列表,其唯一元素为新的 ExportEntry 记录 { [[ModuleRequest]]: null, [[ImportName]]: null, [[LocalName]]: localName, [[ExportName]]: "default" }。
ExportDeclaration : export default ClassDeclaration
  1. namesClassDeclarationBoundNames
  2. localNamenames 的唯一元素。
  3. 返回一个列表,其唯一元素为新的 ExportEntry 记录 { [[ModuleRequest]]: null, [[ImportName]]: null, [[LocalName]]: localName, [[ExportName]]: "default" }。
ExportDeclaration : export default AssignmentExpression ;
  1. entryExportEntry 记录 { [[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 (ModuleRequest 记录或 null) and returns ExportEntry 记录的列表. It is defined piecewise over the following productions:

ExportFromClause : *
  1. entryExportEntry 记录 { [[ModuleRequest]]: module, [[ImportName]]: all-but-default, [[LocalName]]: null, [[ExportName]]: null }。
  2. 返回 « entry »。
ExportFromClause : * as ModuleExportName
  1. exportNameModuleExportNameStringValue
  2. entryExportEntry 记录 { [[ModuleRequest]]: module, [[ImportName]]: namespace, [[LocalName]]: null, [[ExportName]]: exportName }。
  3. 返回 « entry »。
NamedExports : { }
  1. 返回一个新的空列表。
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. 返回一个列表,其唯一元素为新的 ExportEntry 记录 { [[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. 返回一个列表,其唯一元素为新的 ExportEntry 记录 { [[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 解析节点列表. It is defined piecewise over the following productions:

NamedExports : { }
  1. 返回一个新的空列表。
ExportsList : ExportsList , ExportSpecifier
  1. names1ExportsListReferencedBindings
  2. names2ExportSpecifierReferencedBindings
  3. 返回 names1names2 的列表拼接结果。
ExportSpecifier : ModuleExportName as ModuleExportName
  1. 返回第一个 ModuleExportNameReferencedBindings
ModuleExportName : IdentifierName
  1. 返回一个列表,其唯一元素为该 IdentifierName
ModuleExportName : StringLiteral
  1. 返回一个列表,其唯一元素为该 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. env正在运行的执行上下文的 LexicalEnvironment。
    2. 执行 ? InitializeBoundName("*default*", value, env)。
  4. 返回 empty
ExportDeclaration : export default AssignmentExpression ;
  1. 如果 IsAnonymousFunctionDefinition(AssignmentExpression) 是 true,则
    1. value 为以 "default" 为参数的 AssignmentExpression 的 ? NamedEvaluation
  2. 否则,
    1. rhs 为 ? AssignmentExpressionEvaluation
    2. value 为 ? GetValue(rhs)。
  3. env正在运行的执行上下文的 LexicalEnvironment。
  4. 执行 ? InitializeBoundName("*default*", value, env)。
  5. 返回 empty