@@ -2805,6 +2805,7 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
2805
2805
<li><dfn data-x="concept-fetch-terminate" data-x-href="https://fetch.spec.whatwg.org/#concept-fetch-terminate">terminate</dfn></li>
2806
2806
<li>the <dfn data-x-href="https://fetch.spec.whatwg.org/#requestcredentials"><code>RequestCredentials</code></dfn> enumeration</li>
2807
2807
<li>the <dfn data-x-href="https://fetch.spec.whatwg.org/#requestdestination"><code>RequestDestination</code></dfn> enumeration</li>
2808
+ <li>the <dfn data-x-href="https://fetch.spec.whatwg.org/#dom-global-fetch"><code>fetch()</code></dfn> method</li>
2808
2809
<li>
2809
2810
<dfn data-x="concept-response"
2810
2811
data-x-href="https://fetch.spec.whatwg.org/#concept-response">response</dfn> and its
@@ -91365,6 +91366,19 @@ scheduleWork(); // queues a task to do lots of work</code></pre>
91365
91366
91366
91367
<h3>Microtask queuing</h3>
91367
91368
91369
+ <dl class="domintro">
91370
+ <dt><var>self</var> . <code subdfn
91371
+ data-x="dom-queueMicrotask">queueMicrotask</code>(<var>callback</var>)</dt>
91372
+ <dd><p><span data-x="queue a microtask">Queues</span> a <span>microtask</span> to run the given
91373
+ <var>callback</var>.</p></dd>
91374
+ </dl>
91375
+
91376
+ <p w-nodev>The <dfn><code
91377
+ data-x="dom-queueMicrotask">queueMicrotask(<var>callback</var>)</code></dfn> method must
91378
+ <span>queue a microtask</span> to <span data-x="es-invoking-callback-functions">invoke</span>
91379
+ <var>callback</var>, and if <var>callback</var> throws an exception, <span>report the
91380
+ exception</span>.</p>
91381
+
91368
91382
<p>The <code data-x="dom-queueMicrotask">queueMicrotask()</code> method allows authors to schedule
91369
91383
a callback on the <span>microtask queue</span>. This allows their code to run after the
91370
91384
currently-executing <span data-x="concept-task">task</span> has run to completion and the
@@ -91380,18 +91394,94 @@ scheduleWork(); // queues a task to do lots of work</code></pre>
91380
91394
before the next rendering cycle, that is the purpose of <code
91381
91395
data-x="dom-window-requestAnimationFrame">requestAnimationFrame()</code>.</p>
91382
91396
91383
- <dl class="domintro">
91384
- <dt><var>self</var> . <code subdfn
91385
- data-x="dom-queueMicrotask">queueMicrotask</code>(<var>callback</var>)</dt>
91386
- <dd><p><span data-x="queue a microtask">Queues</span> a <span>microtask</span> to run the given
91387
- <var>callback</var>.</p></dd>
91388
- </dl>
91397
+ <p>As can be seen from the following examples, the best way of thinking about <code
91398
+ data-x="dom-queueMicrotask">queueMicrotask()</code> is as a mechanism for rearranging synchronous
91399
+ code, effectively placing the queued code immediately after the current task's worth of non-queued
91400
+ JavaScript.</p>
91389
91401
91390
- <p w-nodev>The <dfn><code
91391
- data-x="dom-queueMicrotask">queueMicrotask(<var>callback</var>)</code></dfn> method must
91392
- <span>queue a microtask</span> to <span data-x="es-invoking-callback-functions">invoke</span>
91393
- <var>callback</var>, and if <var>callback</var> throws an exception, <span>report the
91394
- exception</span>.</p>
91402
+ <div class="example">
91403
+ <p>The most common reason for using <code data-x="dom-queueMicrotask">queueMicrotask()</code> is
91404
+ to create consistent ordering, even in the cases where information is available synchronously,
91405
+ without introducing undue delay.</p>
91406
+
91407
+ <p>For example, consider a custom element firing a <code data-x="">load</code> event, that also
91408
+ maintains an internal cache of previously-loaded data. A naïve implementation might look
91409
+ like:</p>
91410
+
91411
+ <pre><code class="js" data-x="">MyElement.prototype.loadData = function (url) {
91412
+ if (this._cache[url]) {
91413
+ this._setData(this._cache[url]);
91414
+ this.dispatchEvent(new Event("load"));
91415
+ } else {
91416
+ fetch(url).then(res => res.arrayBuffer()).then(data => {
91417
+ this._cache[url] = data;
91418
+ this._setData(data);
91419
+ this.dispatchEvent(new Event("load"));
91420
+ });
91421
+ }
91422
+ };</code></pre>
91423
+
91424
+ <p>This naïve implementation is problematic, however, in that it causes its users to
91425
+ experience inconsistent behavior. For example, code such as</p>
91426
+
91427
+ <pre><code class="js" data-x="">element.addEventListener("load", () => console.log("loaded"));
91428
+ console.log("1");
91429
+ element.loadData();
91430
+ console.log("2");</code></pre>
91431
+
91432
+ <p>will sometimes log "1, 2, loaded" (if the data needs to be fetched), and sometimes log "1,
91433
+ loaded, 2" (if the data is already cached). Similarly, after the call to <code
91434
+ data-x="">loadData()</code>, it will be inconsistent whether or not the data is set on the
91435
+ element.</p>
91436
+
91437
+ <p>To get a consistent ordering, <code data-x="dom-queueMicrotask">queueMicrotask()</code> can be
91438
+ used:</p>
91439
+
91440
+ <pre><code class="js" data-x="">MyElement.prototype.loadData = function (url) {
91441
+ if (this._cache[url]) {<strong>
91442
+ queueMicrotask(() => {
91443
+ this._setData(this._cache[url]);
91444
+ this.dispatchEvent(new Event("load"));
91445
+ });</strong>
91446
+ } else {
91447
+ fetch(url).then(res => res.arrayBuffer()).then(data => {
91448
+ this._cache[url] = data;
91449
+ this._setData(data);
91450
+ this.dispatchEvent(new Event("load"));
91451
+ });
91452
+ }
91453
+ };</code></pre>
91454
+
91455
+ <p>By essentially rearranging the queued code to be after the currently-executing task, this
91456
+ ensures a consistent ordering and update of the element's state.</p>
91457
+ </div>
91458
+
91459
+ <div class="example">
91460
+ <p>Another interesting use of <code data-x="dom-queueMicrotask">queueMicrotask()</code> is to
91461
+ allow uncoordinated "batching" of work by multiple callers. For example, consider a library
91462
+ function that wants to send data somewhere as soon as possible, but doesn't want to make multiple
91463
+ network requests if doing so is easily avoidable. One way to balance this would be like so:</p>
91464
+
91465
+ <pre><code class="js" data-x="">const queuedToSend = [];
91466
+
91467
+ function sendData(data) {
91468
+ queuedToSend.push(data);
91469
+
91470
+ if (queuedToSend.length === 1) {
91471
+ queueMicrotask(() => {
91472
+ const stringToSend = JSON.stringify(queuedToSend);
91473
+ queuedToSend.length = 0;
91474
+
91475
+ fetch("/endpoint", string);
91476
+ });
91477
+ }
91478
+ }</code></pre>
91479
+
91480
+ <p>With this architecture, multiple subsequent calls to <code data-x="">sendData()</code> within
91481
+ the same turn of the event loop will be batched together into one <code>fetch()</code> call, but
91482
+ with no intervening event loop tasks preempting the fetch (as would have happened with similar
91483
+ code that instead used <code data-x="dom-setTimeout">setTimeout()</code>).</p>
91484
+ </div>
91395
91485
91396
91486
91397
91487
<h3>User prompts</h3>
0 commit comments