You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
首先确保没有错误情况。当主机首次调用 A.Link(),假设其正常完成,且递归地链接模块 B 和模块 C,例如:
A.[[Status]]=B.[[Status]]=C.[[Status]]=linked
该预备步骤可以随时执行。之后,当主机准备好承受模块任何可能的副作用时,可以调用 A.Evaluate(),成功完成(再次假设),递归的先 C 后 B 进行求值。此时每个模块的 [[Status]] 为 evaluated.
然后考虑涉及链接错误的情况。如果 C 的 InnerModuleLinking 成功但是,之后 B 失败了,例如 B 引入了 C 没有提供的某些东西,之后原先的 A.Link() 也会失败,同时,A 和 B 的 [[Status]] 仍然保持 unlinked 值。即使 C 的 [[Status]] 已经改为了 linked。
最终,考虑到涉及求值错误情况。如果 C 的 InnerModuleEvaluation 成功但是,之后 B 失败了,例如 B 包含的代码抛出了异常,那么原先的 A.Evaluate() 将会失败。该异常会记录在 A 和 B 的 [[EvaluationError]] 字段,且它们的 [[Status]] 会改为 evaluated。C 也会改为 evaluated 但是,与 A 和 B 相反,不会携带 [[EvaluationError]],因为 C 成功完成了。存储异常确保无论何时主机尝试通过调用 A 和 B 的 Evaluate() 方法重用 A 和 B 模块,都会得到相同的异常。(主机不需要重用循环模块记录;类似地,主机不需要暴露对象通过这些方法抛出的异常。但是,规范可以启用。)
此处我们确保进入点是模块 A,这样主机通过调用 A.Link() 进行操作,即在模块 A 上执行 InnerModuleLinking。依次调用模块 B 上的 InnerModuleLinking。由于循环,再次触发模块 A 上的 InnerModuleLinking,但是当 A.[[Status]] 已经是 linking 状态时进入点为空。B.[[Status]] 保持 linking 状态当控制权从 A 返回且触发 C 的 InnerModuleLinking。之后返回 C.[[Status]],其值为 linked,模块 A 和 B 一起从 linking 过渡到 linked;设计如此,因为它们形成了牢固连接的组建。
在成功的情况下,循环模块图的求值阶段会发生类似的故事。
现在考虑一种情况,A 存在链接错误;例如,它尝试从 C 引入不存在的绑定。这种情况下,上述步骤仍然发生,包含第二次调用提前返回到模块 A 的 InnerModuleLinking。但是,一旦我们退回到模块 A 原先的 InnerModuleLinking,在 InitializeEnvironment 期间失败的话,即在 C.ResolveExport() 之后。引发的 SyntaxError 异常传播到 A.Link,重置当前堆栈中所有模块(它们仍然是 linking 状态)。因此,A 和 B 都变为 unlinked。 请注意,C 保持 linked 状态。
最后,考虑这种情况,A 出现求值错误;例如,其源码抛出异常。在这种情况下,上述步骤的求值时间模拟仍然发生,包含从第二次调用 A 的 InnerModuleEvaluation 早期返回。但是,一旦我们退回到原先 A 的 InnerModuleEvaluation,它因假设而失败。抛出的异常过渡到 A.Evaluate(),记录当前堆栈上所有模块的错误(例如,仍然是 evaluating 状态的模块)。因此,A 和 B 都变为 evaluated 且 A 和 B 的 [[EvaluationError]] 字段都会记录异常,然而 C 保持 evaluated 且没有 [[EvaluationError]]。
The text was updated successfully, but these errors were encountered:
modules:循环模块记录
LexicallyDeclaredNames
抽象模块记录
模块记录封装有关单个模块的导入和导出的结构信息。此信息用于链接已连接模块集的导入和导出。模块记录包含四个字段,仅在求值时使用。
出于规范目的,模块记录值是 Record 类型值且可以认为它存在于简单的面向对象的层次结构中,其中模块记录是具有抽象和具体子类的抽象类。该规范定义名为 Cyclic Module Record 的抽象子类且其具体子类命名为 Source Text Module Record。其它规范和实现可能会定义与它们定义的可选的模块定义功能相对应的其它模块记录子类。
模块记录定义的字段在下表列出。所有模块定义的子类都包含这些字段。模块记录也定义抽象方法在下面第二个表中列出。所有模块定义子类必须提供这些抽象方法的具体实现。
/
undefined/
undefined/
undefined"*namespace*"
。如果名称不能被解析则返回null
,如果有多个绑定则返回"ambiguous"
。每次该运算被指定的 exportName 调用,resolveSet 对作为参数,如果正常完成,则必须返回相同的结果。
调用此方法之前,链接必须已成功完成。
循环模块记录(Cyclic Module Records)
循环模块记录 用于表示有关模块的信息,该模块可以与作为循环模块记录类型的子类的其他模块一起参与依赖性循环。非循环模块记录类型的子类的模块记录禁止和 源文本模块记录(Source Text Module Records) 参与依赖性循环。
除了 模块记录字段 表中定义的字段,循环模块记录还定义了下表中的额外字段:
/
linking/
linked/
evaluating/
evaluated/
undefined/
undefined/
undefined除了 模块记录方法 表中定义的方法,循环模块记录还定义了下表中的额外方法:
Link() 具体方法
循环模块记录的 Link 具体方法实现模块记录对应的 抽象方法。(类似java中接口和具体实现的关系)
成功的话,Link 将模块的 [[Status]] 从 unlinked 过渡到 linked。失败的话,抛出异常且模块的 [[Status]] 仍然是 unlinked。
步骤(绝大部分工作由辅助函数 InnerModuleLinking 完成):
Evaluate() 具体方法
Evaluate 会将模块的 [[Status]] 从 linked 过渡到 evaluated。
如果执行结果为异常,该异常被记录在 [[EvaluationError]] 字段内且被将来的求值调用重新抛出。
步骤(绝大部分工作由辅助函数 InnerModuleEvaluation 完成):
循环模块记录图示例
首先考虑接下来的模块图:
首先确保没有错误情况。当主机首次调用 A.Link(),假设其正常完成,且递归地链接模块 B 和模块 C,例如:
该预备步骤可以随时执行。之后,当主机准备好承受模块任何可能的副作用时,可以调用 A.Evaluate(),成功完成(再次假设),递归的先 C 后 B 进行求值。此时每个模块的 [[Status]] 为 evaluated.
然后考虑涉及链接错误的情况。如果 C 的 InnerModuleLinking 成功但是,之后 B 失败了,例如 B 引入了 C 没有提供的某些东西,之后原先的 A.Link() 也会失败,同时,A 和 B 的 [[Status]] 仍然保持 unlinked 值。即使 C 的 [[Status]] 已经改为了 linked。
最终,考虑到涉及求值错误情况。如果 C 的 InnerModuleEvaluation 成功但是,之后 B 失败了,例如 B 包含的代码抛出了异常,那么原先的 A.Evaluate() 将会失败。该异常会记录在 A 和 B 的 [[EvaluationError]] 字段,且它们的 [[Status]] 会改为 evaluated。C 也会改为 evaluated 但是,与 A 和 B 相反,不会携带 [[EvaluationError]],因为 C 成功完成了。存储异常确保无论何时主机尝试通过调用 A 和 B 的 Evaluate() 方法重用 A 和 B 模块,都会得到相同的异常。(主机不需要重用循环模块记录;类似地,主机不需要暴露对象通过这些方法抛出的异常。但是,规范可以启用。)
链接和求值错误间的差异是由于求值只能执行一次,因为它可能会引起副作用;记住求值是否已被执行是相当重要的,即使求值失败。(在这些错误情况下,意味着也需要记住异常否则之后的 Evaluate() 调用将不得不合成一个新的异常。)另一方面来说,链接无副作用,且即使失败,以后也可以重试,不会有问题。
现在考虑另一种错误情况:
在这种情况下,模块 A 声明对其他模块的依赖,但是那个模块没有 模块记录,例如,当请求 HostResolveImportedModule 时会抛异常。有多种原因能引起这种情况,例如相关资源不存在,或资源存在但是当尝试用 ParseModule 解析结果源文本时抛异常。主机可以选择通过 HostResolveImportedModule 抛出的异常来暴露失败原因。任何情况下,异常都会引起链接错误,这与以前导致 A 的 [[Status]] 保持 unlinked 状态一样。
最后,考虑考虑下循环模块图:
此处我们确保进入点是模块 A,这样主机通过调用 A.Link() 进行操作,即在模块 A 上执行 InnerModuleLinking。依次调用模块 B 上的 InnerModuleLinking。由于循环,再次触发模块 A 上的 InnerModuleLinking,但是当 A.[[Status]] 已经是 linking 状态时进入点为空。B.[[Status]] 保持 linking 状态当控制权从 A 返回且触发 C 的 InnerModuleLinking。之后返回 C.[[Status]],其值为 linked,模块 A 和 B 一起从 linking 过渡到 linked;设计如此,因为它们形成了牢固连接的组建。
在成功的情况下,循环模块图的求值阶段会发生类似的故事。
现在考虑一种情况,A 存在链接错误;例如,它尝试从 C 引入不存在的绑定。这种情况下,上述步骤仍然发生,包含第二次调用提前返回到模块 A 的 InnerModuleLinking。但是,一旦我们退回到模块 A 原先的 InnerModuleLinking,在 InitializeEnvironment 期间失败的话,即在 C.ResolveExport() 之后。引发的 SyntaxError 异常传播到 A.Link,重置当前堆栈中所有模块(它们仍然是 linking 状态)。因此,A 和 B 都变为 unlinked。 请注意,C 保持 linked 状态。
最后,考虑这种情况,A 出现求值错误;例如,其源码抛出异常。在这种情况下,上述步骤的求值时间模拟仍然发生,包含从第二次调用 A 的 InnerModuleEvaluation 早期返回。但是,一旦我们退回到原先 A 的 InnerModuleEvaluation,它因假设而失败。抛出的异常过渡到 A.Evaluate(),记录当前堆栈上所有模块的错误(例如,仍然是 evaluating 状态的模块)。因此,A 和 B 都变为 evaluated 且 A 和 B 的 [[EvaluationError]] 字段都会记录异常,然而 C 保持 evaluated 且没有 [[EvaluationError]]。
The text was updated successfully, but these errors were encountered: