Skip to content

Commit

Permalink
Normative: Synchronous based on a syntax and module graph
Browse files Browse the repository at this point in the history
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
  • Loading branch information
littledan committed Mar 19, 2019
1 parent bffd914 commit 6d26b76
Show file tree
Hide file tree
Showing 2 changed files with 177 additions and 59 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -272,9 +272,9 @@ Currently (in a world without top-level `await`), polyfills are synchronous. So,
#### Does the `Promise.all` happen even if none of the imported modules have a top-level `await`?
Yes. In particular, if none of the imported modules have a top-level `await`, there will still be a delay of some turns on the Promise job queue until the module body executes. The goal here is to avoid too much synchronous behavior, which would break if something turns out to be asynchronous in the future, or even alternate between those two depending on runtime conditions ("releasing Zalgo"). Similar considerations led to the decision that `await` should always be asynchronous, even if passed a non-Promise.
If the module's execution is deterministically synchronous synchronous (that is, if it and its dependencies each contain no top-level `await`), there will be no entry in the `Promise.all` for that module. In this case, it will run synchronously.
Note, this is an observable change from current ES Module semantics, where the Evaluate phase is entirely synchronous. For a concrete example and further discussion, see [issue #43](https://github.com/tc39/proposal-top-level-await/issues/43) and [#47](https://github.com/tc39/proposal-top-level-await/issues/47).
These semantics preserve the current behavior of ES Modules, where, when top-level `await` is not used, the Evaluate phase is entirely synchronous. The semantics are a bit in contrast with uses of Promises elsewhere. For a concrete example and further discussion, see [issue #43](https://github.com/tc39/proposal-top-level-await/issues/43) and [#47](https://github.com/tc39/proposal-top-level-await/issues/47).
#### Does top-level `await` increase the risk of deadlocks?
Expand Down
Loading

0 comments on commit 6d26b76

Please sign in to comment.