-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Top-level await integration #4352
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2653,6 +2653,8 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute | |
| sequence of Unicode scalar values</dfn></li> | ||
| <li><dfn data-x-href="https://heycam.github.io/webidl/#dfn-overload-resolution-algorithm">overload resolution algorithm</dfn></li> | ||
| <li><dfn data-x="idl-exposed" data-x-href="https://heycam.github.io/webidl/#dfn-exposed">exposed</dfn></li> | ||
| <li><dfn data-x-href="https://heycam.github.io/webidl/#a-promise-rejected-with">a promise rejected with</dfn></li> | ||
| <li><dfn data-x-href="https://heycam.github.io/webidl/#upon-rejection">upon rejection</dfn></li> | ||
| <li><dfn data-x="LegacyFactoryFunction" data-x-href="https://heycam.github.io/webidl/#LegacyFactoryFunction"><code>[LegacyFactoryFunction]</code></dfn></li> | ||
| <li><dfn data-x="LegacyLenientThis" data-x-href="https://heycam.github.io/webidl/#LegacyLenientThis"><code>[LegacyLenientThis]</code></dfn></li> | ||
| <li><dfn data-x="LegacyNullToEmptyString" data-x-href="https://heycam.github.io/webidl/#LegacyNullToEmptyString"><code>[LegacyNullToEmptyString]</code></dfn></li> | ||
|
|
@@ -2866,6 +2868,9 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute | |
|
|
||
| <p>Users agents that support JavaScript must also implement <cite>ECMAScript | ||
| Internationalization API</cite>. <ref spec=JSINTL></p> | ||
|
|
||
| <p>User agents that support JavaScript must also implement the <cite>Top-Level Await</cite> | ||
| proposal. <ref spec=JSTLA></p> | ||
| </dd> | ||
|
|
||
|
|
||
|
|
@@ -90353,11 +90358,9 @@ document.querySelector("button").addEventListener("click", bound); | |
| <h5 id="calling-scripts">Calling scripts</h5> | ||
|
|
||
| <p>To <dfn export>run a classic script</dfn> given a <span>classic script</span> <var>script</var> | ||
| and an optional <var>rethrow errors</var> boolean:</p> | ||
| and an optional boolean <var>rethrow errors</var> (default false):</p> | ||
|
|
||
| <ol> | ||
| <li><p>If <var>rethrow errors</var> is not given, let it be false.</p></li> | ||
|
|
||
| <li><p>Let <var>settings</var> be the <span>settings object</span> of <var>script</var>.</p></li> | ||
|
|
||
| <li><p><span>Check if we can run script</span> with <var>settings</var>. If this returns "do | ||
|
|
@@ -90434,25 +90437,23 @@ document.querySelector("button").addEventListener("click", bound); | |
| </p></li> | ||
| </ol> | ||
|
|
||
| <p>To <dfn export>run a module script</dfn> given a <span>module script</span> <var>script</var>, | ||
| with an optional <var>rethrow errors</var> boolean:</p> | ||
| <p>To <dfn export>run a module script</dfn> given a <span>module script</span> <var>script</var> | ||
| and an optional boolean <var>preventErrorReporting</var> (default false):</p> | ||
|
|
||
| <ol> | ||
| <li><p>If <var>rethrow errors</var> is not given, let it be false.</p></li> | ||
|
|
||
| <li><p>Let <var>settings</var> be the <span>settings object</span> of <var>script</var>.</p></li> | ||
|
|
||
| <li><p><span>Check if we can run script</span> with <var>settings</var>. If this returns "do | ||
| not run" then return <span>NormalCompletion</span>(empty).</p></li> | ||
| not run", then return a promise resolved with undefined.</p></li> | ||
|
|
||
| <li><p><span>Prepare to run script</span> given <var>settings</var>.</p></li> | ||
|
|
||
| <li><p>Let <var>evaluationStatus</var> be null.</p></li> | ||
|
Ms2ger marked this conversation as resolved.
|
||
| <li><p>Let <var>evaluationPromise</var> be null.</p></li> | ||
|
|
||
| <li><p>If <var>script</var>'s <span data-x="concept-script-error-to-rethrow">error to | ||
| rethrow</span> is not null, then set <var>evaluationStatus</var> to Completion { [[Type]]: throw, | ||
| [[Value]]: <var>script</var>'s <span data-x="concept-script-error-to-rethrow">error to | ||
| rethrow</span>, [[Target]]: empty }.</p></li> | ||
| rethrow</span> is not null, then set <var>evaluationPromise</var> to <span>a promise rejected | ||
| with</span> <var>script</var>'s <span data-x="concept-script-error-to-rethrow">error to | ||
| rethrow</span>.</p></li> | ||
|
|
||
| <li> | ||
| <p>Otherwise:</p> | ||
|
|
@@ -90462,35 +90463,26 @@ document.querySelector("button").addEventListener("click", bound); | |
| data-x="concept-script-record">record</span>.</p> | ||
|
|
||
| <li> | ||
| <p>Set <var>evaluationStatus</var> to <var>record</var>.<span | ||
| <p>Set <var>evaluationPromise</var> to <var>record</var>.<span | ||
| data-x="js-Evaluate">Evaluate</span>().</p> | ||
|
|
||
| <p class="note">This step will recursively evaluate all of the module's dependencies.</p> | ||
|
|
||
| <p>If <span data-x="js-Evaluate">Evaluate</span> fails to complete as a result of the user agent | ||
| <span data-x="abort a running script">aborting the running script</span>, then set | ||
| <var>evaluationStatus</var> to Completion { [[Type]]: throw, [[Value]]: a new | ||
| <span>"<code>QuotaExceededError</code>"</span> <code>DOMException</code>, [[Target]]: empty | ||
| }.</p> | ||
| <var>evaluationPromise</var> to <span>a promise rejected with</span> a new | ||
| <span>"<code>QuotaExceededError</code>"</span> <code>DOMException</code>.</p> | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can't the user agent abort a module evaluation after the first
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, very interesting. So an instance of the case we're wondering about is <script type="module">
try {
await import("./bad.mjs");
} catch (e) {
// e should ideally be a "QuotaExceededError" DOMException
}
</script>// bad.mjs
await 1;
while (true) { }
await 2;Any ideas what implementations are planning to do, @codehag and @camillobruni?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good find! I tested in Chrome that an infinite looping module can hang the renderer when dynamically imported. The slow script killer doesn't kill dynamic imports correctly, even without top-level await. That is, the following also hangs: <script>
(async function() {
await import("./bad.mjs");
} catch (e) {
// e should ideally be a "QuotaExceededError" DOMException
}
})();
</script>// bad.mjs
while (true) { }Filed https://bugs.chromium.org/p/chromium/issues/detail?id=1157321 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can confirm that firefox has the same behavior as what @syg described for chrome above: both the test cases result in the tab hanging. We do show a user prompt however, about a slow script and let the user respond. When the user responds on the second use case, the script is stopped and the page becomes usable again. Crashes with TLA though. The bug tracking this on the firefox side is https://bugzilla.mozilla.org/show_bug.cgi?id=1681664 cc @annevk
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Alright. A simpler example without dynamic import is the following: <script>
window.onerror = event => {
console.log(event.error); // should ideally log a "QuotaExceededError" DOMException
};
</script>
<script type="module">
await 1;
while (true) { }
</script>I'll try and work on some spec text giving UAs license to terminate top-level-await using scripts in the same way they are currently given license to terminate other scripts, and I'll be sure it also covers dynamic import(). I might merge this first if the fix seems especially separable.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is looking like more of a mess than I thought. The script-killing section of the spec isn't very well defined or aligned with UAs; e.g. as far as I can tell from Chrome it kills the entire process after prompting, which is not really allowed by the current spec text. And we're not sure if any browser actually bothers with the "QuotaExceededError" DOMException business. So I'll merge this as-is and file a followup bug. |
||
| </li> | ||
| </ol> | ||
| </li> | ||
|
|
||
| <li> | ||
| <p>If <var>evaluationStatus</var> is an <span>abrupt completion</span>, then:</p> | ||
|
|
||
| <ol> | ||
| <li><p>If <var>rethrow errors</var> is true, rethrow the exception given by | ||
| <var>evaluationStatus</var>.[[Value]].</p></li> | ||
|
|
||
| <li><p>Otherwise, <span>report the exception</span> given by | ||
| <var>evaluationStatus</var>.[[Value]] for <var>script</var>.</p></li> | ||
| </ol> | ||
| </li> | ||
| <li><p>If <var>preventErrorReporting</var> is false, then <span>upon rejection</span> of | ||
| <var>evaluationPromise</var> with <var>reason</var>, <span>report the exception</span> given by | ||
| <var>reason</var> for <var>script</var>.</p></li> | ||
|
|
||
| <li><p><span>Clean up after running script</span> with <var>settings</var>.</p></li> | ||
|
|
||
| <li><p>Return <var>evaluationStatus</var>.</p></li> | ||
| <li><p>Return <var>evaluationPromise</var>.</p></li> | ||
| </ol> | ||
|
|
||
| <p>The steps to <dfn>check if we can run script</dfn> with an <span>environment settings | ||
|
|
@@ -91241,30 +91233,16 @@ import "https://example.com/foo/../module2.mjs";</code></pre> | |
| URL</var>, <var>settings object</var>, and <var>fetch options</var>. Wait until the algorithm | ||
| asynchronously completes with <var>result</var>.</p></li> | ||
|
|
||
| <li> | ||
| <p>If <var>result</var> is null, then:</p> | ||
|
|
||
| <ol> | ||
| <li><p>Let <var>completion</var> be Completion { [[Type]]: throw, [[Value]]: a new | ||
| <code>TypeError</code>, [[Target]]: empty }.</p></li> | ||
|
|
||
| <li><p>Perform <span>FinishDynamicImport</span>(<var>referencingScriptOrModule</var>, | ||
| <var>specifier</var>, <var>promiseCapability</var>, <var>completion</var>).</p></li> | ||
|
|
||
| <li><p>Return.</p></li> | ||
| </ol> | ||
| </li> | ||
| <li><p>Let <var>promise</var> be null. | ||
|
|
||
| <li><p><span data-x="run a module script">Run the module script</span> <var>result</var>, with | ||
| the rethrow errors boolean set to true.</p></li> | ||
| <li><p>If <var>result</var> is null, then set <var>promise</var> to <span>a promise rejected | ||
| with</span> a new <code>TypeError</code>.</p></li> | ||
|
Ms2ger marked this conversation as resolved.
Outdated
|
||
|
|
||
| <li><p>If running the module script throws an exception, then perform | ||
| <span>FinishDynamicImport</span>(<var>referencingScriptOrModule</var>, <var>specifier</var>, | ||
| <var>promiseCapability</var>, the thrown exception completion).</p></li> | ||
| <li><p>Otherwise, set <var>promise</var> to the result of <span data-x="run a module | ||
| script">running a module script</span> given <var>result</var> and true.</p></li> | ||
|
|
||
| <li><p>Otherwise, perform | ||
| <span>FinishDynamicImport</span>(<var>referencingScriptOrModule</var>, <var>specifier</var>, | ||
| <var>promiseCapability</var>, <span>NormalCompletion</span>(undefined)).</p></li> | ||
| <li><p>Perform <span>FinishDynamicImport</span>(<var>referencingScriptOrModule</var>, | ||
| <var>specifier</var>, <var>promiseCapability</var>, <var>promise</var>).</p></li> | ||
|
|
||
| <li><p>Return undefined.</p></li> | ||
| </ol> | ||
|
|
@@ -123109,6 +123087,9 @@ INSERT INTERFACES HERE | |
| <dt id="refsJSINTL">[JSINTL]</dt> | ||
| <dd><cite><a href="https://tc39.es/ecma402/">ECMAScript Internationalization API Specification</a></cite>. Ecma International.</dd> | ||
|
|
||
| <dt id="refsJSTLA">[JSTLA]</dt> | ||
| <dd><cite><a href="https://tc39.es/proposal-top-level-await/">Top-Level Await</a></cite>. Ecma International.</dd> | ||
|
|
||
| <dt id="refsJSON">[JSON]</dt> | ||
| <dd><cite><a href="https://tools.ietf.org/html/rfc7159">The JavaScript Object Notation (JSON) Data Interchange Format</a></cite>, T. Bray. IETF.</dd> | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.