Skip to content

Commit

Permalink
Handle error cases during module script tree fetching/running better
Browse files Browse the repository at this point in the history
As discussed in #1545 and in
https://esdiscuss.org/topic/moduledeclarationinstantiation-behaviour-after-failure,
the spec would potentially call ModuleDeclarationInstantiation on a
module that previously failed to instantiate, with cascading bad
consequences for the rest of the spec's algorithms. The JavaScript spec
expects us to track these failures and avoid calling
ModuleDeclarationInstantiation a second time. This commit adds such
state tracking, partially by moving the ModuleDeclarationInstantiation
calls to fetch time (with any errors stored for later rethrowing during
evaluation time).

Fixes #1545.
  • Loading branch information
domenic authored Aug 9, 2016
1 parent 7b56772 commit e1af867
Showing 1 changed file with 144 additions and 26 deletions.
170 changes: 144 additions & 26 deletions source
Original file line number Diff line number Diff line change
Expand Up @@ -85956,6 +85956,27 @@ interface <dfn>NavigatorOnLine</dfn> {

</dd>

<dt>An <dfn data-x="concept-module-script-instantiation-state">instantiation state</dfn></dt>

<dd>

<p>One of "<code data-x="">uninstantiated</code>", "<code data-x="">errored</code>", or "<code
data-x="">instantiated</code>", used to prevent reinvocation of <span
data-x="js-ModuleDeclarationInstantiation">ModuleDeclarationInstantiation</span> on modules that
failed to instantiate previously.</p>

</dd>

<dt>An <dfn data-x="concept-module-script-instantiation-error">instantiation error</dfn></dt>

<dd>

<p>A JavaScript value, which has meaning only if the <span
data-x="concept-module-script-instantiation-state">instantiation state</span> is "<code
data-x="">errored</code>".</p>

</dd>

<dt>A <dfn data-x="concept-module-script-credentials-mode">credentials mode</dfn></dt>

<dd>
Expand Down Expand Up @@ -86385,13 +86406,103 @@ interface <dfn>NavigatorOnLine</dfn> {
<li><p>Otherwise, <var>result</var> is a <span>module script</span>. <span data-x="fetch the
descendants of a module script">Fetch the descendants</span> of <var>result</var> given
<var>destination</var> and an ancestor list obtained by appending <var>url</var> to <var>ancestor
list</var>.</p></li>
list</var>. Wait for <span data-x="fetch the descendants of a module script">fetching the
descendants of a module script</span> to asynchronously complete with <var>descendants
result</var> before proceeding to the next step.</p></li>

<li><p>Let <var>record</var> be <var>result</var>'s <span
data-x="concept-module-script-module-record">module record</span>.</p>

<li>
<p>Let <var>instantiationStatus</var> be <var>record</var>.<span
data-x="js-ModuleDeclarationInstantiation">ModuleDeclarationInstantiation</span>().</p>

<li><p>When <span data-x="fetch the descendants of a module script">fetching the descendants of
a module script</span> asynchronously completes with <var>descendants result</var>,
asynchronously complete this algorithm with <var>descendants result</var>.</p></li>
<p class="note">This step will recursively call <span
data-x="js-ModuleDeclarationInstantiation">ModuleDeclarationInstantiation</span> all of the
module's uninstantiated dependencies.</p>
</li>

<li>
<p>For each <span>module script</span> <var>script</var> in <var>result</var>'s
<span>uninstantiated inclusive descendant module scripts</span>, perform the following
steps:</p>

<ol>
<li><p>If <var>instantiationStatus</var> is an abrupt completion, then set <var>script</var>'s
<span data-x="concept-module-script-instantiation-state">instantiation state</span> to "<code
data-x="">errored</code>", its <span
data-x="concept-module-script-instantiation-error">instantiation error</span> to
<var>instantiationStatus</var>.[[Value]], and its <span
data-x="concept-module-script-module-record">module record</span> to null.</p></li>

<li><p>Otherwise, set <var>script</var>'s <span
data-x="concept-module-script-instantiation-state">instantiation state</span> to "<code
data-x="">instantiated</code>".</p></li>
</ol>
</li>

<li>
<p>Asynchronously complete this algorithm with <var>descendants result</var>.</p>

<p class="note">It is intentional that we complete with <var>descendants result</var> here, and
not <var>result</var>, as this allows us to propagate error signals to the caller.</p>
</li>
</ol>

<p>In the above algorithm, a <span>module script</span> <var>script</var>'s <dfn>uninstantiated
inclusive descendant module scripts</dfn> is a set of <span data-x="module script">module
scripts</span> determined as follows:</p>

<ol>
<li><p>Let <var>module map</var> be <var>script</var>'s <span>settings object</span>'s
<span>module map</span>.</p></li>

<li><p>Let <var>stack</var> be a list containing <var>script</var>.</p></li>

<li><p>Let <var>inclusive descendants</var> be an empty set.</p></li>

<li>
<p>While <var>stack</var> is not empty:</p>

<ol>
<li><p>Let <var>current</var> be the last element of <var>stack</var>. Remove it from
<var>stack</var>.</p></li>

<li>
<p>If <var>current</var> is not in <var>inclusive descendants</var> and is not in
<var>stack</var>, then:</p>

<ol>
<li><p>Add <var>current</var> to <var>inclusive descendants</var>.</p></li>

<li><p>Let <var>child specifiers</var> be the value of <var>current</var>'s <span
data-x="concept-module-script-module-record">module record</span>'s [[RequestedModules]]
internal slot.</p></li>

<li><p>Let <var>child URLs</var> be the set obtained by calling <span>resolve a module
specifier</span> once for each element of <var>child specifiers</var>, given
<var>current</var> and that element. Omit any failures.</p></li>

<li><p>Let <var>child modules</var> be the set obtained by looking up each value in
<var>module map</var> whose key is given by an element of <var>child URLs</var>.</p></li>

<li><p>For each <var>s</var> in <var>child modules</var> that is not in <var>inclusive
descendants</var>, add <var>s</var> to <var>stack</var>.</p></li>
</ol>
</li>
</ol>
</li>

<li><p>Return a list containing all elements of <var>inclusive descendants</var> whose <span
data-x="concept-module-script-instantiation-state">instantiation state</span> is "<code
data-x="">uninstantiated</code>".</p></li>
</ol>

<p class="note">The above algorithm gives a depth-first search of the module dependency graph. The
main interesting part is in how the "edges" of this graph are determined. The actual search
implementation is not important; any other technique for exploring the graph will suffice, given
that the output is an unordered set.</p>

<p>To <dfn>fetch a single module script</dfn>, given a <var>url</var>, a <var>fetch client
settings object</var>, a <var>destination</var>, a <var>cryptographic nonce</var>, a <var>parser
state</var>, a <var>credentials mode</var>, a <var>module map settings object</var>, a
Expand Down Expand Up @@ -86539,13 +86650,9 @@ interface <dfn>NavigatorOnLine</dfn> {
<span data-x="fetching-scripts-perform-fetch">perform the fetch</span> steps, pass those along
while performing the <span>internal module script tree fetching procedure</span>.</p>

<p>If any of the <span>internal module script tree fetching procedure</span> invocations
asynchronously complete with null, the user agent may <span
data-x="concept-fetch-terminate">terminate</span> any or all of the other fetches, and must then
asynchronously complete this algorithm with null.</p>

<p>Once all of the <span>internal module script tree fetching procedure</span> invocations
asynchronously complete with a <span>module script</span>, asynchronously complete this
<p>Wait for all of the <span>internal module script tree fetching procedure</span> invocations
to asynchronously complete. If any of them asynchronously complete with null, then
asynchronously complete this algorithm with null. Otherwise, asynchronously complete this
algorithm with <var>module script</var>.</p>
</li>
</ol>
Expand Down Expand Up @@ -86696,19 +86803,19 @@ interface <dfn>NavigatorOnLine</dfn> {
<li><p><span>Check if we can run script</span> with <var>settings</var>. If this returns "do
not run" then abort these steps.</p></li>

<li><p>Let <var>record</var> be <var>s</var>'s <span
data-x="concept-module-script-module-record">module record</span>.</p>

<li>
<p>Let <var>instantiationStatus</var> be <var>record</var>.<span
data-x="js-ModuleDeclarationInstantiation">ModuleDeclarationInstantiation</span>().</p>
<li><p>If <var>s</var>'s <span data-x="concept-module-script-instantiation-state">instantiation
state</span> is "<code data-x="">errored</code>", then <span>report the
exception</span> given by <var>s</var>'s <span
data-x="concept-module-script-instantiation-error">instantiation error</span> for <var>s</var>
and abort these steps.</p></li>

<p class="note">This step will recursively instantiate all of the module's dependencies.</p>
</li>
<li><p>Assert: <var>s</var>'s <span
data-x="concept-module-script-instantiation-state">instantiation state</span> is "<code
data-x="">instantiated</code>" (and thus its <span
data-x="concept-module-script-module-record">module record</span> is not null).</p></li>

<li><p>If <var>instantiationStatus</var> is an abrupt completion, <span>report the
exception</span> given by <var>instantiationStatus</var>.[[Value]] for <var>s</var> and abort
these steps.</p></li>
<li><p>Let <var>record</var> be <var>s</var>'s <span
data-x="concept-module-script-module-record">module record</span>.</p>

<li><p><span>Prepare to run script</span> given <var>settings</var>.</p></li>

Expand All @@ -86719,10 +86826,11 @@ interface <dfn>NavigatorOnLine</dfn> {
<p class="note">This step will recursively evaluate all of the module's dependencies.</p>
</li>

<li><p>If <var>evaluationStatus</var> is an abrupt completion, <span>report the exception</span>
given by <var>evaluationStatus</var>.[[Value]] for <var>s</var>. (Do not perform this step if
<span data-x="js-ModuleEvaluation">ModuleEvaluation</span> fails to complete as a result of the
user agent <span data-x="abort a running script">aborting the running script</span>.)</p></li>
<li><p>If <var>evaluationStatus</var> is an abrupt completion, then <span>report the
exception</span> given by <var>evaluationStatus</var>.[[Value]] for <var>s</var>. (Do not perform
this step if <span data-x="js-ModuleEvaluation">ModuleEvaluation</span> fails to complete as a
result of the user agent <span data-x="abort a running script">aborting the running
script</span>.)</p></li>

<li><p><span>Clean up after running script</span> with <var>settings</var>.</p></li>
</ol>
Expand Down Expand Up @@ -87506,6 +87614,16 @@ document.querySelector("button").addEventListener("click", bound);
data-x="">fetching</code>", throw a <code>TypeError</code> exception and abort these
steps.</p></li>

<li><p>If <var>resolved module script</var>'s <span
data-x="concept-module-script-instantiation-state">instantiation state</span> is "<code
data-x="">errored</code>", then throw <var>resolved module script</var>'s <span
data-x="concept-module-script-instantiation-error">instantiation error</span>.</p></li>

<li><p>Assert: <var>resolved module script</var>'s <span
data-x="concept-module-script-instantiation-state">instantiation state</span> is "<code
data-x="">instantiated</code>" (and thus its <span
data-x="concept-module-script-module-record">module record</span> is not null).</p></li>

<li><p>Return <var>resolved module script</var>'s <span
data-x="concept-module-script-module-record">module record</span>.</p></li>
</ol>
Expand Down

0 comments on commit e1af867

Please sign in to comment.