-
Notifications
You must be signed in to change notification settings - Fork 46
Normative: Avoid microtask queue delay when resolved #49
Conversation
Note, this is one of two possible solutions. I'm working on a writeup of how this would be solved instead through a microtask queue checkpoint. |
cc @GeorgNeis |
There is a possible tweak to this patch, where we only treat a module as synchronous if it completed synchronously the first time, and so any top-level await (even from a previous module graph traversal) will always take a turn through the job queue before the module runs. Maybe this would ameliorate the "Zalgo" concerns a little bit, but it would require extra bookkeeping. |
spec.html
Outdated
@@ -357,7 +357,7 @@ <h1>InnerModuleEvaluation( _module_, _stack_, _index_ )</h1> | |||
1. <ins>Let _evalCapability_ be ! NewPromiseCapability(%Promise%).</ins> | |||
1. <ins>Set _module_.[[ExecPromise]] to _evalCapability_.[[Promise]]. | |||
1. Set _index_ to _index_ + 1. | |||
1. Append _module_ to _stack_. | |||
1. Append _module_. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like a typo?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
0cdf693
to
ab2344e
Compare
Applied #49 (comment) in |
This patch is a variant on tc39#49 which determines which module subgraphs are to be executed synchronously based on syntax (whether the module contains a top-level await syntactically) and the dependency graph (whether it imports a module which contains a top-level await, recursively). This fixed check is designed to be more predictable and analyzable. Abstract module record changes: - The [[Async]] field stores whether this module or dependencies are async. It is expected to be initialized by the Linking phase. - The [[ExecutionPromise]] field stores the Promise related to the evaluation of a module whose [[Async]] field is *true*. - Evaluate() returns a Promise for [[Async]] modules, a completion record for sync modules which throw, or undefined otherwise. Cyclic Module Record changes: - A new [[ModuleAsync]] field stores whether this particular module is asynchronous (dependencies aside). - The ExecuteModule method on Cyclic Module Records takes an argument for the Promise capability, but only if that particular module is [[ModuleAsync]]. - The Link/Instantiate phase is used to propagate the [[Async]] field up the module graph to dependencies. - When there's a cycle, with some modules sync and some async, the whole cycle is considered async, with the Promise of each module set to the entrypoint of the cycle, although the cycle-closing edge will not actually be awaited (since this would be a deadlock). Source Text Module Record changes: - The check for whether a module contains a top-level await locally is in a ContainsAwait algorithm (TBD writing this out, but it should be static since await may not appear in a direct eval) - Module execution works as before if ContainsAwait is false, and works like an async function if ContainsAwait is true. Closes tc39#47, tc39#48, tc39#43
I would prefer to not take this approach, as it leaves whether a module is async or not up to whether it dynamically hits an await, as opposed to whether one is syntactically present (as in the current proposal). So, closing this PR. |
Closes #47, #48, #43