<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Async-Await on ENKR's Blog | Jing Hui PANG</title><link>https://blog.enkr1.com/tags/async-await/</link><description>Recent content in Async-Await on ENKR's Blog | Jing Hui PANG</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><copyright>ENKR</copyright><lastBuildDate>Thu, 15 Oct 2026 14:05:30 +0800</lastBuildDate><atom:link href="https://blog.enkr1.com/tags/async-await/index.xml" rel="self" type="application/rss+xml"/><item><title>Microtasks Jump the Queue: Reading Promise, await and setTimeout Order</title><link>https://blog.enkr1.com/microtasks-jump-the-queue/</link><pubDate>Sun, 11 Oct 2026 18:25:20 +0800</pubDate><guid>https://blog.enkr1.com/microtasks-jump-the-queue/</guid><description>&lt;blockquote&gt;
&lt;p&gt;a while back i spent an evening grinding through promise-ordering puzzles with chatgpt: &lt;code&gt;setTimeout&lt;/code&gt; against &lt;code&gt;Promise.resolve&lt;/code&gt; against &lt;code&gt;await&lt;/code&gt;, which line prints first. i never wrote any of it down, so when i went looking for it later there was nothing to find. this note is the version i should have written then. my AI helped me rebuild the puzzles, and i ran every single one in node (v22) so the printed order below is what actually came out, not what either of us expected. the personal note at the bottom is mine to write after.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="tldr"&gt;tl;dr
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;the whole game is two queues. run one &lt;strong&gt;task&lt;/strong&gt; to the end, then drain &lt;strong&gt;every&lt;/strong&gt; microtask, then take the next task. promise callbacks and the code after an &lt;code&gt;await&lt;/code&gt; are microtasks. &lt;code&gt;setTimeout&lt;/code&gt;, &lt;code&gt;setInterval&lt;/code&gt;, I/O and UI events are tasks.&lt;/li&gt;
&lt;li&gt;so &lt;code&gt;Promise.resolve().then(...)&lt;/code&gt; beats &lt;code&gt;setTimeout(..., 0)&lt;/code&gt; every time, and everything before the first &lt;code&gt;await&lt;/code&gt; in an async function runs synchronously.&lt;/li&gt;
&lt;li&gt;answers online disagree because the rules moved: since V8 7.2 (late 2018) an &lt;code&gt;await&lt;/code&gt; on a native promise costs one microtask tick instead of three. returning a promise from a &lt;code&gt;.then&lt;/code&gt; or an async function still costs two extra ticks.&lt;/li&gt;
&lt;li&gt;the traps that hurt in real code are not the puzzles, they are &lt;code&gt;await&lt;/code&gt; inside a loop, async callbacks in &lt;code&gt;forEach&lt;/code&gt;/&lt;code&gt;map&lt;/code&gt;, and a &lt;code&gt;try&lt;/code&gt; that never awaits.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-question"&gt;the question
&lt;/h2&gt;&lt;p&gt;these puzzles look like trivia: eight &lt;code&gt;console.log&lt;/code&gt; lines and a &amp;ldquo;what prints?&amp;rdquo;. but every one of them is really asking the same thing, which is whether you know what the runtime does &lt;em&gt;between&lt;/em&gt; your lines of code. get the model right and every puzzle is mechanical. get it wrong and you will also ship the real bugs: a loop that is five times slower than it needs to be, or an error that sails straight past your &lt;code&gt;catch&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;so this is the model, then the puzzles in rising difficulty, then the traps.&lt;/p&gt;
&lt;h2 id="the-model-one-task-then-all-the-microtasks"&gt;the model: one task, then all the microtasks
&lt;/h2&gt;&lt;p&gt;javascript runs on one thread. the host (a browser or node) keeps queues of work waiting for that thread, and the event loop pulls from them in a fixed rhythm:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;take &lt;strong&gt;one task&lt;/strong&gt; from the task queue and run it to completion. the main script itself is the first task.&lt;/li&gt;
&lt;li&gt;when the call stack is empty, run &lt;strong&gt;every microtask&lt;/strong&gt; in the microtask queue. if a microtask queues another microtask, that one runs in this same drain too.&lt;/li&gt;
&lt;li&gt;(browser only) maybe render a frame.&lt;/li&gt;
&lt;li&gt;go back to 1.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;what lands where:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;queue&lt;/th&gt;
&lt;th&gt;what puts work there&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;task (also called macrotask)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;setTimeout&lt;/code&gt;, &lt;code&gt;setInterval&lt;/code&gt;, I/O callbacks, UI events, &lt;code&gt;setImmediate&lt;/code&gt; in node, &lt;code&gt;MessageChannel&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;microtask&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.then&lt;/code&gt; / &lt;code&gt;.catch&lt;/code&gt; / &lt;code&gt;.finally&lt;/code&gt; callbacks, the rest of an async function after &lt;code&gt;await&lt;/code&gt;, &lt;code&gt;queueMicrotask&lt;/code&gt;, &lt;code&gt;MutationObserver&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;two details that the puzzles lean on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the function you pass to &lt;code&gt;new Promise(fn)&lt;/code&gt; runs &lt;strong&gt;synchronously&lt;/strong&gt;, right now. only the &lt;code&gt;.then&lt;/code&gt; callbacks are deferred.&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;.then&lt;/code&gt; callback is queued only once its promise &lt;em&gt;settles&lt;/em&gt;. on an already-resolved promise that is immediately; on a pending one it is whenever it resolves.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;that is genuinely all of it. the rest is tracing.&lt;/p&gt;
&lt;h2 id="the-puzzles"&gt;the puzzles
&lt;/h2&gt;&lt;p&gt;try each one before reading the answer.&lt;/p&gt;
&lt;h3 id="1-the-warm-up"&gt;1. the warm-up
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;2&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;3&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;c&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;4&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;d&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;prints &lt;code&gt;a d c b&lt;/code&gt;.&lt;/strong&gt; &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;d&lt;/code&gt; are part of the current task. &lt;code&gt;c&lt;/code&gt; is a microtask, so it runs as soon as the script finishes. &lt;code&gt;b&lt;/code&gt; is a new task, so it waits for the microtask drain. a delay of &lt;code&gt;0&lt;/code&gt; does not mean &amp;ldquo;now&amp;rdquo;, it means &amp;ldquo;in a later task&amp;rdquo;.&lt;/p&gt;
&lt;h3 id="2-the-first-await"&gt;2. the first await
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;2&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;3&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;4&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;5&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;6&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;7&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;prints &lt;code&gt;1 3 2&lt;/code&gt;.&lt;/strong&gt; calling an async function runs its body synchronously up to the first &lt;code&gt;await&lt;/code&gt;. the &lt;code&gt;await&lt;/code&gt; hands control back to the caller and queues the rest of the body as a microtask. awaiting a non-promise like &lt;code&gt;null&lt;/code&gt; still yields: &lt;code&gt;await&lt;/code&gt; always waits at least one tick.&lt;/p&gt;
&lt;h3 id="3-the-classic"&gt;3. the classic
&lt;/h3&gt;&lt;p&gt;this is the one that shows up everywhere, and it has every moving part in it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;async1&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 2&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;async1 start&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 3&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;async2&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 4&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;async1 end&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 5&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 6&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;async2&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 7&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;async2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 8&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 9&lt;/span&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;10&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;script start&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;11&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;setTimeout&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;12&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;async1&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;13&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;14&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;promise1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;15&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;16&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;promise2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;17&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;script end&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;prints:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;1&lt;/span&gt;&lt;span class="cl"&gt;script start
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;2&lt;/span&gt;&lt;span class="cl"&gt;async1 start
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;3&lt;/span&gt;&lt;span class="cl"&gt;async2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;4&lt;/span&gt;&lt;span class="cl"&gt;promise1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;5&lt;/span&gt;&lt;span class="cl"&gt;script end
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;6&lt;/span&gt;&lt;span class="cl"&gt;async1 end
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;7&lt;/span&gt;&lt;span class="cl"&gt;promise2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;8&lt;/span&gt;&lt;span class="cl"&gt;setTimeout
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;the trace, step by step:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;step&lt;/th&gt;
&lt;th&gt;runs&lt;/th&gt;
&lt;th&gt;task queue after&lt;/th&gt;
&lt;th&gt;microtask queue after&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;script start&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;code&gt;setTimeout&lt;/code&gt; is scheduled&lt;/td&gt;
&lt;td&gt;timer&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;code&gt;async1()&lt;/code&gt; logs &lt;code&gt;async1 start&lt;/code&gt;, calls &lt;code&gt;async2()&lt;/code&gt; which logs &lt;code&gt;async2&lt;/code&gt; and returns a resolved promise&lt;/td&gt;
&lt;td&gt;timer&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;code&gt;await&lt;/code&gt; parks &lt;code&gt;async1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;timer&lt;/td&gt;
&lt;td&gt;rest of async1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;the promise executor logs &lt;code&gt;promise1&lt;/code&gt; and resolves&lt;/td&gt;
&lt;td&gt;timer&lt;/td&gt;
&lt;td&gt;rest of async1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.then&lt;/code&gt; queues on the resolved promise&lt;/td&gt;
&lt;td&gt;timer&lt;/td&gt;
&lt;td&gt;rest of async1, promise2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;&lt;code&gt;script end&lt;/code&gt;, the script task is done&lt;/td&gt;
&lt;td&gt;timer&lt;/td&gt;
&lt;td&gt;rest of async1, promise2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;drain microtasks: &lt;code&gt;async1 end&lt;/code&gt;, then &lt;code&gt;promise2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;timer&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;next task: &lt;code&gt;setTimeout&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;the bits people miss: &lt;code&gt;async2&lt;/code&gt; prints during the synchronous phase (it is just a function call), &lt;code&gt;promise1&lt;/code&gt; prints synchronously (executors are not deferred), and &lt;code&gt;async1 end&lt;/code&gt; beats &lt;code&gt;promise2&lt;/code&gt; because it was queued first.&lt;/p&gt;
&lt;h3 id="4-two-chains-interleave"&gt;4. two chains interleave
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;2&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;prints &lt;code&gt;1 3 2 4&lt;/code&gt;&lt;/strong&gt;, not &lt;code&gt;1 2 3 4&lt;/code&gt;. the second &lt;code&gt;.then&lt;/code&gt; in each chain is not queued until the first one has run and resolved its promise. so the first drain sees only &lt;code&gt;1&lt;/code&gt; and &lt;code&gt;3&lt;/code&gt;; running them queues &lt;code&gt;2&lt;/code&gt; and &lt;code&gt;4&lt;/code&gt; behind them. chains advance one link per tick, side by side.&lt;/p&gt;
&lt;h3 id="5-the-expensive-return"&gt;5. the expensive return
&lt;/h3&gt;&lt;p&gt;this is the hard one, and it is the one that tests whether you are counting ticks or guessing:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 2&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 3&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 4&lt;/span&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 5&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 6&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 7&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 8&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 9&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;10&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;prints &lt;code&gt;0 1 2 3 4 5 6&lt;/code&gt;.&lt;/strong&gt; if returning a value cost one tick like every other link, &lt;code&gt;4&lt;/code&gt; would print right after &lt;code&gt;1&lt;/code&gt;. it lands after &lt;code&gt;3&lt;/code&gt; instead, because returning a &lt;em&gt;promise&lt;/em&gt; (any thenable) from a &lt;code&gt;.then&lt;/code&gt; callback costs &lt;strong&gt;two extra ticks&lt;/strong&gt;: the spec first queues a job that calls &lt;code&gt;.then&lt;/code&gt; on your returned promise, and only when &lt;em&gt;that&lt;/em&gt; reaction fires does the outer promise resolve and queue the next link.&lt;/p&gt;
&lt;p&gt;the same thing happens when an async function returns a promise:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;a1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;a2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;2&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;b1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;3&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;4&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;t1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;t2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;5&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;t3&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;t4&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;prints &lt;code&gt;a1 b1 t1 t2 a2 t3 t4&lt;/code&gt;.&lt;/strong&gt; two extra ticks for &lt;code&gt;b&lt;/code&gt;&amp;rsquo;s returned promise, then one for the &lt;code&gt;await&lt;/code&gt;. you will almost never care about this in real code, but it is why &amp;ldquo;just count the thens&amp;rdquo; fails on the harder puzzles.&lt;/p&gt;
&lt;h3 id="6-node-adds-two-more-queues"&gt;6. node adds two more queues
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;timeout&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;2&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;setImmediate&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;immediate&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;3&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;promise&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;4&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nextTick&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;nextTick&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;5&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;sync&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;this one has a genuinely surprising answer, because &lt;strong&gt;it depends on the file type&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;as CommonJS (&lt;code&gt;.cjs&lt;/code&gt;, or &lt;code&gt;.js&lt;/code&gt; without &lt;code&gt;&amp;quot;type&amp;quot;: &amp;quot;module&amp;quot;&lt;/code&gt;): &lt;code&gt;sync nextTick promise immediate timeout&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;as an ES module (&lt;code&gt;.mjs&lt;/code&gt;): &lt;code&gt;sync promise nextTick immediate timeout&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;node&amp;rsquo;s &lt;code&gt;process.nextTick&lt;/code&gt; queue normally drains &lt;em&gt;before&lt;/em&gt; the promise microtask queue. but an ES module&amp;rsquo;s top-level code is itself evaluated as part of the microtask queue, so node is already mid-drain when your promise callback joins, and it runs first. the node docs spell this out in the section on &lt;code&gt;queueMicrotask()&lt;/code&gt; versus &lt;code&gt;process.nextTick()&lt;/code&gt;. that is one more reason they recommend &lt;code&gt;queueMicrotask&lt;/code&gt; over &lt;code&gt;nextTick&lt;/code&gt; for ordinary deferral.&lt;/p&gt;
&lt;p&gt;and the last two are not even stable. i ran that file twenty times from the main module: &lt;code&gt;immediate&lt;/code&gt; came before &lt;code&gt;timeout&lt;/code&gt; nineteen times, and the other way round once. the node docs call this order non-deterministic, because it depends on whether the 1ms timer has expired by the time the loop first checks. inside an I/O callback (say, in a &lt;code&gt;fs.readFile&lt;/code&gt; callback) &lt;code&gt;setImmediate&lt;/code&gt; always wins, because the check phase comes straight after the poll phase.&lt;/p&gt;
&lt;h2 id="why-the-answers-online-disagree"&gt;why the answers online disagree
&lt;/h2&gt;&lt;p&gt;if you search puzzle 3 you will find older posts that print &lt;code&gt;promise2&lt;/code&gt; &lt;em&gt;before&lt;/em&gt; &lt;code&gt;async1 end&lt;/code&gt;. they were not wrong for their time.&lt;/p&gt;
&lt;p&gt;the spec used to wrap every awaited value in a fresh promise and resolve it through the thenable path, which cost &lt;strong&gt;three&lt;/strong&gt; microtask ticks per &lt;code&gt;await&lt;/code&gt; even when the value was already a native promise. in 2018 the V8 team proposed a spec change (ecma262 PR #1250) that awaits a native promise directly, in &lt;strong&gt;one&lt;/strong&gt; tick. it shipped on by default in V8 7.2 / Chrome 72, and the V8 blog post &amp;ldquo;Faster async functions and promises&amp;rdquo; walks through it. node picked it up from node 12.&lt;/p&gt;
&lt;p&gt;so for any puzzle involving &lt;code&gt;await&lt;/code&gt;, the answer is &amp;ldquo;modern engines print X&amp;rdquo;. an older runtime, or an older blog post, may print Y. the two-tick cost of returning a promise (puzzle 5) is still there, because that part of the spec did not change.&lt;/p&gt;
&lt;h2 id="where-people-get-this-wrong"&gt;where people get this wrong
&lt;/h2&gt;&lt;p&gt;the puzzles are a party trick. these are the ones that ship bugs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;await&lt;/code&gt; in a &lt;code&gt;for&lt;/code&gt; loop serialises the work.&lt;/strong&gt; three independent 20ms calls:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetchOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// ~63ms, one after another
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;2&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;fetchOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="c1"&gt;// ~20ms, all at once
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;that is from an actual run. if the calls do not depend on each other, start them all and await the batch. if there are hundreds, cap the concurrency with a small pool so you do not open five hundred sockets at once.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;forEach&lt;/code&gt; does not wait for async callbacks.&lt;/strong&gt; &lt;code&gt;ids.forEach(async id =&amp;gt; await save(id))&lt;/code&gt; returns immediately (0ms in my run), and anything after it runs before a single save has finished. &lt;code&gt;forEach&lt;/code&gt; throws the returned promises away. use &lt;code&gt;for...of&lt;/code&gt; with &lt;code&gt;await&lt;/code&gt; for sequential work, or &lt;code&gt;Promise.all&lt;/code&gt; with &lt;code&gt;map&lt;/code&gt; for parallel.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;an async &lt;code&gt;map&lt;/code&gt; gives you promises, not values.&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;u&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetchId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;2&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;// a Promise, not an id
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;fix: &lt;code&gt;const ids = await Promise.all(users.map(u =&amp;gt; fetchId(u)))&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;a &lt;code&gt;try&lt;/code&gt; that does not await catches nothing.&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;2&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;doThing&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;3&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;4&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// never runs for an async failure
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;5&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;the rejection happens in a later microtask, long after the &lt;code&gt;try&lt;/code&gt; block has exited. either &lt;code&gt;await&lt;/code&gt; inside the &lt;code&gt;try&lt;/code&gt;, or put &lt;code&gt;.catch(log)&lt;/code&gt; on the chain.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Promise.all&lt;/code&gt; fails fast, but does not cancel.&lt;/strong&gt; reject one input and &lt;code&gt;Promise.all&lt;/code&gt; rejects immediately (0ms in my run), but the other promises keep running to completion in the background; my 30ms timer still fired after the catch. there is no cancellation unless you wire one in, usually with an &lt;code&gt;AbortController&lt;/code&gt;. pick the combinator that matches what you need:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;combinator&lt;/th&gt;
&lt;th&gt;settles when&lt;/th&gt;
&lt;th&gt;you get&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Promise.all&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;all fulfil, or the first rejects&lt;/td&gt;
&lt;td&gt;array of values, or the first error&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Promise.allSettled&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;all settle, never rejects&lt;/td&gt;
&lt;td&gt;&lt;code&gt;{ status, value | reason }&lt;/code&gt; per input&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Promise.race&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;the first settles, either way&lt;/td&gt;
&lt;td&gt;that value or that error&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Promise.any&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;the first fulfils&lt;/td&gt;
&lt;td&gt;that value, or an &lt;code&gt;AggregateError&lt;/code&gt; if all reject&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;microtasks can starve the loop.&lt;/strong&gt; because a drain runs until the microtask queue is empty, a microtask that keeps queueing microtasks blocks timers, I/O and rendering. on my laptop, a &lt;code&gt;setTimeout(..., 0)&lt;/code&gt; waited 163ms behind two million self-queueing microtasks. if you need to yield to the rest of the world, schedule a &lt;em&gt;task&lt;/em&gt; (&lt;code&gt;setTimeout&lt;/code&gt;, &lt;code&gt;MessageChannel&lt;/code&gt;), not a microtask.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;setTimeout(fn, 0)&lt;/code&gt; is not zero.&lt;/strong&gt; node turns any delay below 1 into 1ms, and browsers clamp deeply nested zero-delay timers up to about 4ms. it means &amp;ldquo;after the current task and its microtasks&amp;rdquo;, never &amp;ldquo;now&amp;rdquo;.&lt;/p&gt;
&lt;h2 id="key-takeaways"&gt;key takeaways
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;one task, then drain every microtask, then the next task. that sentence answers most puzzles.&lt;/li&gt;
&lt;li&gt;promise callbacks and post-&lt;code&gt;await&lt;/code&gt; code are microtasks. timers and I/O are tasks.&lt;/li&gt;
&lt;li&gt;an async function is synchronous up to its first &lt;code&gt;await&lt;/code&gt;; a promise executor is synchronous, full stop.&lt;/li&gt;
&lt;li&gt;chains advance one link per tick, so parallel chains interleave.&lt;/li&gt;
&lt;li&gt;returning a promise from &lt;code&gt;.then&lt;/code&gt; or an async function costs two extra ticks.&lt;/li&gt;
&lt;li&gt;in node, &lt;code&gt;nextTick&lt;/code&gt; beats promises in CommonJS but not in ES modules, and &lt;code&gt;setImmediate&lt;/code&gt; versus &lt;code&gt;setTimeout(0)&lt;/code&gt; is a coin toss from the main module.&lt;/li&gt;
&lt;li&gt;in real code: do not &lt;code&gt;await&lt;/code&gt; in a loop over independent work, do not hand async callbacks to &lt;code&gt;forEach&lt;/code&gt;, and do not expect a &lt;code&gt;try&lt;/code&gt; to catch what it did not &lt;code&gt;await&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;i used &lt;code&gt;Promise.all&lt;/code&gt; to wait on every image and API call before finishing the bar in &lt;a class="link" href="https://blog.enkr1.com/building-a-dynamic-and-smooth-progress-bar-for-web-loading/" &gt;building a loading progress bar that tracks every resource&lt;/a&gt;, which is a concrete case of &amp;ldquo;start everything, await the batch&amp;rdquo;. the rest of my javascript scraps live in the &lt;a class="link" href="https://blog.enkr1.com/javascript-notebook/" &gt;javascript notebook&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="a-personal-note"&gt;a personal note
&lt;/h2&gt;&lt;p&gt;wip&lt;/p&gt;
&lt;h2 id="sources-and-further-reading"&gt;sources and further reading
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Jake Archibald, &lt;a class="link" href="https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/" target="_blank" rel="noopener"
&gt;&amp;ldquo;Tasks, microtasks, queues and schedules&amp;rdquo;&lt;/a&gt; (2015). the post that made this model famous, with animated step-throughs.&lt;/li&gt;
&lt;li&gt;Maya Armyanova and Benedikt Meurer, &lt;a class="link" href="https://v8.dev/blog/fast-async" target="_blank" rel="noopener"
&gt;&amp;ldquo;Faster async functions and promises&amp;rdquo;&lt;/a&gt;, V8 blog (12 November 2018). the three-ticks-to-one &lt;code&gt;await&lt;/code&gt; change, ecma262 PR #1250, V8 7.2.&lt;/li&gt;
&lt;li&gt;WHATWG, &lt;a class="link" href="https://html.spec.whatwg.org/multipage/webappapis.html#event-loops" target="_blank" rel="noopener"
&gt;HTML Living Standard: event loops&lt;/a&gt; and &lt;a class="link" href="https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers" target="_blank" rel="noopener"
&gt;timers&lt;/a&gt;. the browser task and microtask processing model, and the nested-timer clamp.&lt;/li&gt;
&lt;li&gt;Ecma International, &lt;a class="link" href="https://tc39.es/ecma262/#sec-promise-jobs" target="_blank" rel="noopener"
&gt;ECMAScript language specification: promise jobs&lt;/a&gt;. &lt;code&gt;NewPromiseReactionJob&lt;/code&gt; and &lt;code&gt;NewPromiseResolveThenableJob&lt;/code&gt;, the source of puzzle 5&amp;rsquo;s extra ticks.&lt;/li&gt;
&lt;li&gt;Node.js docs, &lt;a class="link" href="https://nodejs.org/api/process.html#when-to-use-queuemicrotask-vs-processnexttick" target="_blank" rel="noopener"
&gt;&lt;code&gt;process.nextTick()&lt;/code&gt; and &amp;ldquo;When to use queueMicrotask() vs. process.nextTick()&amp;rdquo;&lt;/a&gt;. the CommonJS versus ES module ordering.&lt;/li&gt;
&lt;li&gt;Node.js docs, &lt;a class="link" href="https://nodejs.org/en/learn/asynchronous-work/event-loop-timers-and-nexttick" target="_blank" rel="noopener"
&gt;&amp;ldquo;The Node.js Event Loop&amp;rdquo;&lt;/a&gt;. phases, and why &lt;code&gt;setImmediate&lt;/code&gt; versus &lt;code&gt;setTimeout(0)&lt;/code&gt; is non-deterministic outside an I/O callback.&lt;/li&gt;
&lt;li&gt;MDN, &lt;a class="link" href="https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide" target="_blank" rel="noopener"
&gt;Using microtasks in JavaScript with queueMicrotask()&lt;/a&gt; and &lt;a class="link" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise#promise_concurrency" target="_blank" rel="noopener"
&gt;Promise concurrency&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>