Skip to main content

Command Palette

Search for a command to run...

Js Event loop questions!!

Updated
•109 min read•View as Markdown
Js Event loop questions!!

In a recent interview, my friend was asked an interesting question — and I got it wrong too at first. The trick was that async has higher priority than setTimeout. I later realized why: async returns a Promise, and Promises are handled in the microtask queue, which runs before the macrotask queue where setTimeout lives. That moment led me to create a whole practice sheet on JS task priorities — it really clears up how things actually execute in JavaScript.

So here, we won’t just solve questions — we’ll also use diagrams to understand exactly how the code runs inside the browser engine.

Before we dive into the questions, let’s quickly understand the different queues in JavaScript and how they work together inside the browser engine.

The Big Picture

┌────────────────────────────┐
│        JS Engine           │
│ (Call Stack + Event Loop)  │
└─────────────┬──────────────┘
              │
    ┌─────────┴─────────┐
    │                   │
Microtask Queue     Macrotask Queue
(High Priority)     (Low Priority)
    │                   │
Promises, async/await    setTimeout, setInterval, I/O

1. Call Stack

This isn’t a queue — it’s where your JavaScript runs line by line.
When the call stack is empty, the event loop picks tasks from the queues.

2. Macrotask Queue (Task Queue)

Holds tasks that should run after the current stack finishes.

Includes:

  • setTimeout

  • setInterval

  • setImmediate (Node.js only)

  • DOM events (click, scroll)

  • AJAX callbacks

3. Microtask Queue

Reserved for high-priority async tasks that execute before any macrotasks.

Includes:

  • Promises (.then, .catch, .finally)

  • async/await (since await returns a promise)

  • queueMicrotask()

  • MutationObserver (browser API)

4. Render Queue (Browser Only)

After microtasks and before macrotasks, the browser may:

  • Update the DOM

  • Perform reflows

  • Repaint elements

You can’t directly add tasks here — it’s part of the browser’s rendering cycle.

Simplified Priority Overview

Queue TypeExamplesPriorityWhen It Runs
Call StackNormal JS codeHighestImmediately
MicrotaskPromises, async/await, queueMicrotaskHighAfter current stack, before macrotasks
MacrotasksetTimeout, setInterval, I/OMediumAfter microtasks are done
Render QueueDOM paintingMediumBetween micro/macro cycles
Animation FramerequestAnimationFrameMediumBefore browser repaint

Event Loop Flow

┌───────────────────────┐
│   Call Stack (Run JS) │
└────────────┬──────────┘
             ↓
┌───────────────────────┐
│   Microtask Queue     │ ← Promise, async/await
└────────────┬──────────┘
             ↓
┌───────────────────────┐
│   Render (Browser)    │
└────────────┬──────────┘
             ↓
┌───────────────────────┐
│   Macrotask Queue     │ ← setTimeout, I/O
└───────────────────────┘

We’ll mainly focus on the first three — the Call Stack, Microtask Queue, and Macrotask Queue — since understanding them clearly will help you master JavaScript’s execution order.

Now we have a slightly better picture of the queues and their priority, so let's start with the questions.

console.log('script start');
setTimeout(() => console.log('timeout'), 0);
Promise.resolve().then(() => console.log('promise'));
console.log('script end');

// script start
// script end
// promise
// timeout
StepCall StackWeb APIs / QueuesConsole (so far)
1console.log('script start')——
⏩ After exec——script start
2setTimeout()Web API Timer: [console.log('timeout')]script start
3Promise.resolve() → .then()Web API Timer: [console.log('timeout')]Microtask Queue: [console.log('promise')]script start
4console.log('script end')Web API Timer: [console.log('timeout')]Microtask Queue: [console.log('promise')]script start
⏩ After exec—Web API Timer: [console.log('timeout')]Microtask Queue: [console.log('promise')]script start, script end
5— (Stack empty)🟢 Event Loop picks Microtasksscript start, script end
6console.log('promise')Web API Timer: [console.log('timeout')]script start, script end
⏩ After exec—Web API Timer: [console.log('timeout')]script start, script end, promise
7console.log('timeout') (Macrotask dequeued)—script start, script end, promise
⏩ After exec——script start, script end, promise, timeout

Step-by-Step Explanation

Step 1 — console.log('script start')

  • The line console.log('script start') is placed on the Call Stack and executed immediately because it’s synchronous.

  • It prints 'script start' to the Console.

  • After printing, the stack becomes empty again.

✅ Console now shows: script start

Step 2 — setTimeout(...)

  • The setTimeout() function is added to the Call Stack.

  • The browser (or Node’s environment) moves the callback function
    () => console.log('timeout') to the Web API Timer to wait for 0 milliseconds.

  • After setting up the timer, setTimeout() itself finishes executing and is removed from the stack.

✅ Web API Timer holds: console.log('timeout')
✅ Console remains: script start

Step 3 — Promise.resolve().then(...)

  • Promise.resolve() runs instantly and returns a resolved Promise.

  • The .then() callback (() => console.log('promise')) is placed into the Microtask Queue.

  • The promise itself doesn’t run immediately — it waits until the Call Stack is empty.

✅ Microtask Queue holds: console.log('promise')
✅ Web API Timer still has: console.log('timeout')

Step 4 — console.log('script end')

  • The console.log('script end') runs next — it’s still synchronous.

  • 'script end' is printed to the Console.

  • The Call Stack is now completely empty.

✅ Console now shows: script start, script end

Step 5 — Stack Empty → Event Loop Checks Queues

  • The Call Stack is empty, so the Event Loop starts checking queues.

  • It always gives priority to Microtasks (like Promises) before Macrotasks (like setTimeout).

✅ Next task to run → console.log('promise') from the Microtask Queue.

Step 6 — Run Microtask (console.log('promise'))

  • The promise callback moves from the Microtask Queue to the Call Stack.

  • It executes console.log('promise'), printing 'promise' to the console.

  • After execution, the Microtask Queue becomes empty.

✅ Console now shows:
script start, script end, promise

Step 7 — Run Macrotask (console.log('timeout'))

  • Now that all Microtasks are done, the Event Loop moves to the Macrotask Queue.

  • The callback from setTimeout is taken from the Web API Timer and moved into the Call Stack.

  • It executes console.log('timeout'), printing 'timeout'.

  • After it finishes, everything is empty again.

async function foo() {
  console.log('foo start');
  await null;
  console.log('foo end');
}
console.log('start');
foo();
console.log('end');

// start
// foo start
// end
// foo end
StepCall StackWeb APIs / QueuesConsole (so far)
1console.log('start')——
⏩ After exec——start
2foo()—start
3Inside foo: console.log('foo start')—start
⏩ After exec——start, foo start
4await nullMicrotask Queue: [console.log('foo end')]start, foo start
⏩ After exec—Microtask Queue: [console.log('foo end')]start, foo start
5console.log('end')Microtask Queue: [console.log('foo end')]start, foo start
⏩ After exec—Microtask Queue: [console.log('foo end')]start, foo start, end
6— (Stack empty)🟢 Event Loop picks Microtask (foo end)start, foo start, end
7console.log('foo end')—start, foo start, end
⏩ After exec——start, foo start, end, foo end

Step-by-Step Explanation

Step 1 — console.log('start')

  • The first synchronous statement runs immediately and prints "start".
    ✅ Console: start

Step 2 — foo()

  • The async function foo() is called.

  • It enters the Call Stack, and execution begins inside foo.

Step 3 — Inside foo: console.log('foo start')

  • This line executes synchronously and prints "foo start".
    ✅ Console: start, foo start

Step 4 — await null

  • The await expression pauses foo() execution.

  • It schedules the continuation (console.log('foo end')) as a Microtask and returns a pending Promise immediately.

  • The Call Stack clears — the rest of foo() (foo end) will run later.
    ✅ Microtask Queue: console.log('foo end')

Step 5 — console.log('end')

  • The next synchronous line after foo() runs, printing "end".
    ✅ Console: start, foo start, end

Step 6 — Stack Empty → Event Loop runs Microtasks

  • After all synchronous code finishes, the Event Loop checks the Microtask Queue.

  • It finds the continuation of foo() waiting there.

Step 7 — Run Microtask → console.log('foo end')

  • The resumed part of foo() executes, printing "foo end".
    ✅ Final Console: start, foo start, end, foo end
async function foo() {
  console.log('foo');
}
async function bar() {
  console.log('bar start');
  await foo();
  console.log('bar end');
}
bar();
console.log('script');

// bar start
// foo
// script
// bar end

Execution Table

StepCall StackWeb APIs / QueuesConsole (so far)
1bar()——
2Inside bar: console.log('bar start')——
⏩ After exec——bar start
3Inside bar: await foo() → calls foo()—bar start
4Inside foo: console.log('foo')—bar start
⏩ After exec——bar start, foo
5foo() returns resolved Promise → resumes laterMicrotask Queue: [console.log('bar end')]bar start, foo
6console.log('script')Microtask Queue: [console.log('bar end')]bar start, foo
⏩ After exec—Microtask Queue: [console.log('bar end')]bar start, foo, script
7— (Stack empty)🟢 Event Loop picks Microtask (bar end)bar start, foo, script
8console.log('bar end')—bar start, foo, script
⏩ After exec——bar start, foo, script, bar end

Step-by-Step Explanation

Step 1 — Call bar()

  • The function bar() is invoked.

  • It enters the Call Stack.

  • Execution begins inside bar.

Step 2 — console.log('bar start')

  • This synchronous line runs immediately.

  • It prints "bar start" to the console.

  • After execution, control moves to the next line (await foo()).

✅ Console: bar start

Step 3 — await foo()

  • The function foo() is called as part of the await expression.

  • foo() enters the Call Stack and executes synchronously until it hits an await or finishes.

Step 4 — Inside foo: console.log('foo')

  • This line executes synchronously and prints "foo".

  • After this, foo() completes and returns a resolved Promise (because async functions always return Promises).

✅ Console: bar start, foo

Step 5 — Resume behavior of await foo()

  • The await pauses the rest of bar() until the Promise returned by foo() resolves.

  • The continuation (console.log('bar end')) is scheduled as a Microtask.

  • bar() returns a pending Promise and exits the Call Stack.

✅ Microtask Queue: console.log('bar end')

Step 6 — console.log('script')

  • After bar() finishes scheduling the microtask, the next synchronous line runs.

  • It prints "script" immediately.

✅ Console: bar start, foo, script

Step 7 — Stack Empty → Event Loop runs Microtasks

  • Once all synchronous tasks are complete, the Event Loop checks the Microtask Queue.

  • It finds the pending microtask from bar() continuation.

Step 8 — Run Microtask → console.log('bar end')

  • The resumed part of bar() executes.

  • It prints "bar end" to the console.

  • All queues are now empty.

✅ Final Console:
bar start, foo, script, bar end

async function async1() {
  console.log('async1 start');
  await async2();
  console.log('async1 end');
}
async function async2() {
  console.log('async2');
}
console.log('script start');
setTimeout(() => console.log('setTimeout'), 0);
async1();
new Promise(resolve => {
  console.log('promise1');
  resolve();
}).then(() => console.log('promise2'));
console.log('script end');

// script start
// async1 start
// async2
// promise1
// script end
// async1 end
// promise2
// setTimeout

Execution Table

StepCall StackWeb APIs / QueuesConsole (so far)
1console.log('script start')——
⏩ After exec——script start
2setTimeout()Web API Timer: [console.log('setTimeout')]script start
3async1()—script start
4Inside async1: console.log('async1 start')—script start
⏩ After exec——script start, async1 start
5Inside async1: await async2() → calls async2()—script start, async1 start
6Inside async2: console.log('async2')—script start, async1 start
⏩ After exec—Microtask Queue: [console.log('async1 end')]script start, async1 start, async2
7new Promise(...)—script start, async1 start, async2
8Inside Promise executor: console.log('promise1')—script start, async1 start, async2
⏩ After exec—Microtask Queue: [console.log('async1 end'), console.log('promise2')]script start, async1 start, async2, promise1
9console.log('script end')Microtask Queue: [console.log('async1 end'), console.log('promise2')]script start, async1 start, async2, promise1
⏩ After exec—Microtask Queue: [console.log('async1 end'), console.log('promise2')]script start, async1 start, async2, promise1, script end
10— (Stack empty)🟢 Event Loop picks Microtasks (async1 end, then promise2)script start, async1 start, async2, promise1, script end
11Run Microtask → console.log('async1 end')Microtask Queue: [console.log('promise2')]script start, async1 start, async2, promise1, script end
⏩ After exec—Microtask Queue: [console.log('promise2')]script start, async1 start, async2, promise1, script end, async1 end
12Run Microtask → console.log('promise2')—script start, async1 start, async2, promise1, script end, async1 end
⏩ After exec——script start, async1 start, async2, promise1, script end, async1 end, promise2
13Run Macrotask (from Timer): console.log('setTimeout')—script start, async1 start, async2, promise1, script end, async1 end, promise2
⏩ After exec——script start, async1 start, async2, promise1, script end, async1 end, promise2, setTimeout

Step-by-Step Explanation

Step 1 — console.log('script start')

  • Runs first (synchronous code).

  • Prints “script start”.
    ✅ Console: script start

Step 2 — setTimeout(..., 0)

  • setTimeout schedules its callback in the Web API Timer for later (Macrotask).

  • It doesn’t block — returns immediately.
    ✅ Web API Timer: console.log('setTimeout')

Step 3 — async1() call

  • async1() enters the Call Stack and starts executing.

Step 4 — Inside async1: console.log('async1 start')

  • Runs synchronously and prints “async1 start”.
    ✅ Console: script start, async1 start

Step 5 — await async2()

  • Calls async2() immediately.

  • Execution inside async1 pauses at the await.

Step 6 — Inside async2: console.log('async2')

  • Executes synchronously and prints “async2”.

  • Returns a resolved Promise.

  • async1’s continuation (console.log('async1 end')) is placed in the Microtask Queue.
    ✅ Console: script start, async1 start, async2
    ✅ Microtask Queue: console.log('async1 end')

Step 7 — new Promise(...)

  • The Promise constructor executes its function immediately (synchronously).

Step 8 — Inside Promise executor: console.log('promise1')

  • Prints “promise1” synchronously.

  • When resolve() is called, the .then() callback (console.log('promise2')) is queued as a Microtask.
    ✅ Microtask Queue: console.log('async1 end'), console.log('promise2')
    ✅ Console: script start, async1 start, async2, promise1

Step 9 — console.log('script end')

  • Synchronous line — runs immediately.

  • Prints “script end”.
    ✅ Console: script start, async1 start, async2, promise1, script end

Step 10 — Stack Empty → Event Loop checks queues

  • The Call Stack is empty.

  • The Event Loop picks Microtasks first (before Macrotasks).

  • Microtasks to run (in order):

    1. async1 end

    2. promise2

Step 11 — Run Microtask 1 → console.log('async1 end')

  • Prints “async1 end”.
    ✅ Console: script start, async1 start, async2, promise1, script end, async1 end

Step 12 — Run Microtask 2 → console.log('promise2')

  • Prints “promise2”.
    ✅ Console: script start, async1 start, async2, promise1, script end, async1 end, promise2

Step 13 — Run Macrotask → console.log('setTimeout')

  • After all microtasks finish, the Event Loop executes the Macrotask from the timer.

  • Prints “setTimeout”.
    ✅ Final Console:
    script start, async1 start, async2, promise1, script end, async1 end, promise2, setTimeout

console.log('start');
Promise.resolve().then(() => console.log('promise'));
setTimeout(() => console.log('timeout'));
console.log('end');

// start
// end
// promise
// timeout

Execution Table

StepCall StackWeb APIs / QueuesConsole (so far)
1console.log('start')——
⏩ After exec——start
2Promise.resolve().then(...)Microtask Queue: [console.log('promise')]start
3setTimeout(...)Web API Timer: [console.log('timeout')]start
4console.log('end')Web API Timer: [console.log('timeout')] Microtask Queue: [console.log('promise')]start
⏩ After exec—Web API Timer: [console.log('timeout')] Microtask Queue: [console.log('promise')]start, end
5— (Stack empty)🟢 Event Loop picks Microtask (promise)start, end
6console.log('promise')Web API Timer: [console.log('timeout')]start, end
⏩ After exec—Web API Timer: [console.log('timeout')]start, end, promise
7Run Macrotask → console.log('timeout')—start, end, promise
⏩ After exec——start, end, promise, timeout

Step-by-Step Explanation

Step 1 — console.log('start')

  • The first synchronous statement runs immediately.

  • Prints “start” to the console.
    ✅ Console: start

Step 2 — Promise.resolve().then(...)

  • The Promise.resolve() instantly returns a resolved Promise.

  • The .then() callback (console.log('promise')) is scheduled in the Microtask Queue to run after all synchronous code completes.
    ✅ Microtask Queue: console.log('promise')

Step 3 — setTimeout(...)

  • The setTimeout callback is sent to the Web API Timer.

  • It will move to the Macrotask Queue after the delay (0ms).
    ✅ Web API Timer: console.log('timeout')

Step 4 — console.log('end')

  • Another synchronous statement.

  • Runs immediately and prints “end”.
    ✅ Console: start, end

Step 5 — Stack Empty → Event Loop checks Queues

  • After all synchronous code is done, the Call Stack becomes empty.

  • The Event Loop checks for pending tasks.

  • Microtasks (Promises) have higher priority than Macrotasks (setTimeout).
    ✅ Next to run: console.log('promise')

Step 6 — Run Microtask (console.log('promise'))

  • The promise callback executes from the Microtask Queue.

  • Prints “promise”.
    ✅ Console: start, end, promise

Step 7 — Run Macrotask (console.log('timeout'))

  • After all Microtasks are complete, the Event Loop picks the next Macrotask from the Timer Queue.

  • Prints “timeout”.
    ✅ Final Console:
    start, end, promise, timeout

async function a() {
  await b();
  console.log('a end');
}
async function b() {
  console.log('b');
}
console.log('start');
a();
console.log('end');

// start
// b
// end
// a end

Execution Table

StepCall StackWeb APIs / QueuesConsole (so far)
1console.log('start')——
⏩ After exec——start
2a()—start
3Inside a: await b() → calls b()—start
4Inside b: console.log('b')—start
⏩ After exec—Microtask Queue: [console.log('a end')]start, b
5console.log('end')Microtask Queue: [console.log('a end')]start, b
⏩ After exec—Microtask Queue: [console.log('a end')]start, b, end
6— (Stack empty)🟢 Event Loop picks Microtask (a end)start, b, end
7console.log('a end')—start, b, end
⏩ After exec——start, b, end, a end

Step-by-Step Explanation

Step 1 — console.log('start')

  • The first synchronous statement executes immediately.

  • Prints “start” to the console.
    ✅ Console: start

Step 2 — a() call

  • The async function a() is invoked and added to the Call Stack.

  • Execution starts inside a().

Step 3 — Inside a: await b()

  • When await b() runs, it calls the async function b().

  • a() pauses execution at the await point until b()'s Promise resolves.

  • The rest of a() (console.log('a end')) is scheduled as a Microtask.

Step 4 — Inside b: console.log('b')

  • The function b() executes synchronously up to completion.

  • Prints “b” to the console.
    ✅ Console: start, b
    ✅ Microtask Queue: console.log('a end')

Step 5 — console.log('end')

  • The next synchronous statement executes.

  • Prints “end” to the console.
    ✅ Console: start, b, end

Step 6 — Stack Empty → Event Loop runs Microtasks

  • All synchronous code has finished, so the Call Stack is empty.

  • The Event Loop checks the Microtask Queue and finds the continuation of a() (console.log('a end')).

Step 7 — Run Microtask (console.log('a end'))

  • The remaining part of a() executes.

  • Prints “a end” to the console.
    ✅ Final Console: start, b, end, a end

async function test() {
  console.log(1);
  await Promise.resolve();
  console.log(2);
}
test();
console.log(3);

// 1
// 3
// 2

Execution Table

StepCall StackWeb APIs / QueuesConsole (so far)
1test()——
2Inside test: console.log(1)——
⏩ After exec——1
3Inside test: await Promise.resolve()Microtask Queue: [console.log(2)]1
4console.log(3)Microtask Queue: [console.log(2)]1
⏩ After exec—Microtask Queue: [console.log(2)]1, 3
5— (Stack empty)🟢 Event Loop picks Microtask (console.log(2))1, 3
6console.log(2)—1, 3
⏩ After exec——1, 3, 2

Step-by-Step Explanation

Step 1 — test() call

  • The async function test() is invoked and enters the Call Stack.

  • Execution starts inside the function body.

Step 2 — Inside test: console.log(1)

  • This synchronous statement runs immediately.

  • Prints “1” to the console.
    ✅ Console: 1

Step 3 — await Promise.resolve()

  • The Promise.resolve() returns a resolved Promise instantly.

  • Because of the await, the rest of test() (the code after the await) is paused and scheduled as a Microtask (console.log(2)).
    ✅ Microtask Queue: console.log(2)

Step 4 — console.log(3)

  • The next synchronous line after the test() call executes.

  • Prints “3” to the console.
    ✅ Console: 1, 3

Step 5 — Stack Empty → Event Loop runs Microtasks

  • Once all synchronous code finishes, the Call Stack is empty.

  • The Event Loop picks the Microtask (console.log(2) from the async continuation).

Step 6 — Run Microtask (console.log(2))

  • The paused part of test() resumes and runs console.log(2).

  • Prints “2” to the console.
    ✅ Final Console: 1, 3, 2

async function x() {
  console.log('x start');
  await y();
  console.log('x end');
}
async function y() {
  console.log('y');
}
x();
console.log('end');

// x start
// y
// end
// x end

Execution Table

StepCall StackWeb APIs / QueuesConsole (so far)
1x()——
2Inside x: console.log('x start')——
⏩ After exec——x start
3Inside x: await y() → calls y()—x start
4Inside y: console.log('y')—x start
⏩ After exec—Microtask Queue: [console.log('x end')]x start, y
5console.log('end')Microtask Queue: [console.log('x end')]x start, y
⏩ After exec—Microtask Queue: [console.log('x end')]x start, y, end
6— (Stack empty)🟢 Event Loop picks Microtask (console.log('x end'))x start, y, end
7console.log('x end')—x start, y, end
⏩ After exec——x start, y, end, x end

Step-by-Step Explanation

Step 1 — x() call

  • The async function x() is invoked.

  • It enters the Call Stack and starts executing.

Step 2 — Inside x: console.log('x start')

  • Synchronous code executes immediately.

  • Prints “x start” to the console.
    ✅ Console: x start

Step 3 — Inside x: await y()

  • Calls the async function y().

  • The execution of x() pauses after await until y()’s Promise resolves.

  • The remaining code (console.log('x end')) is queued as a Microtask.

Step 4 — Inside y: console.log('y')

  • Runs synchronously and prints “y”.

  • y() finishes and returns a resolved Promise.
    ✅ Console: x start, y
    ✅ Microtask Queue: console.log('x end')

Step 5 — console.log('end')

  • After x() paused, control returns to global synchronous code.

  • Prints “end”.
    ✅ Console: x start, y, end

Step 6 — Stack Empty → Event Loop runs Microtasks

  • Once all synchronous tasks are complete, the Event Loop checks the Microtask Queue.

  • Finds console.log('x end') waiting from x()’s continuation.

Step 7 — Run Microtask (console.log('x end'))

  • Executes the paused part of x().

  • Prints “x end”.
    ✅ Final Console: x start, y, end, x end

async function test() {
  console.log('A');
  await null;
  console.log('B');
}
test();
Promise.resolve().then(() => console.log('C'));
console.log('D');

// A
// D
// B
// C

Execution Table

StepCall StackWeb APIs / QueuesConsole (so far)
1test()——
2Inside test: console.log('A')——
⏩ After exec——A
3Inside test: await null—A
⏩ After exec—Microtask Queue: [console.log('B')]A
4Promise.resolve().then(() => console.log('C'))—A
⏩ After exec—Microtask Queue: [console.log('B'), console.log('C')]A
5console.log('D')Microtask Queue: [console.log('B'), console.log('C')]A
⏩ After exec—Microtask Queue: [console.log('B'), console.log('C')]A, D
6— (Stack empty)🟢 Event Loop picks MicrotasksA, D
7console.log('B')Microtask Queue: [console.log('C')]A, D
⏩ After exec—Microtask Queue: [console.log('C')]A, D, B
8console.log('C')—A, D, B
⏩ After exec——A, D, B, C

Step-by-Step Explanation

Step 1 — test() call

  • The async function test() is invoked.

  • Added to the Call Stack and starts executing.

Step 2 — Inside test: console.log('A')

  • Runs synchronously, so it prints “A” immediately.
    ✅ Console: A

Step 3 — Inside test: await null

  • await null is equivalent to Promise.resolve(null) — it creates a resolved Promise.

  • The rest of test() (console.log('B')) is paused and scheduled as a Microtask.
    ✅ Microtask Queue: console.log('B')

Step 4 — Promise.resolve().then(() => console.log('C'))

  • This schedules another Microtask for “C” to print later.
    ✅ Microtask Queue now: [console.log('B'), console.log('C')]

Step 5 — console.log('D')

  • Runs synchronously in the main script.

  • Prints “D” immediately.
    ✅ Console: A, D

Step 6 — Event Loop starts Microtasks

  • Call Stack is empty → Event Loop picks Microtasks in FIFO order (first-in-first-out).

Step 7 — Execute Microtask: console.log('B')

  • The async function test() resumes and prints “B”.
    ✅ Console: A, D, B

Step 8 — Execute Microtask: console.log('C')

  • The .then() callback runs next and prints “C”.
    ✅ Final Console: A, D, B, C
console.log('start');
setTimeout(() => console.log('timeout1'));
Promise.resolve().then(() => console.log('p1')).then(() => console.log('p2'));
setTimeout(() => console.log('timeout2'));
console.log('end');

// start
// end
// p1
// p2
// timeout1
// timeout2

Execution Table

StepCall StackWeb APIs / QueuesConsole (so far)
1console.log('start')——
⏩ After exec——start
2setTimeout(() => console.log('timeout1'))Web API Timers: [console.log('timeout1')]start
3Promise.resolve().then(() => console.log('p1')).then(() => console.log('p2'))Web API Timers: [timeout1] Microtask Queue: [console.log('p1')]start
4setTimeout(() => console.log('timeout2'))Web API Timers: [timeout1, timeout2] Microtask Queue: [console.log('p1')]start
5console.log('end')Web API Timers: [timeout1, timeout2] Microtask Queue: [console.log('p1')]start
⏩ After exec—Web API Timers: [timeout1, timeout2] Microtask Queue: [console.log('p1')]start, end
6— (Stack empty)🟢 Event Loop picks Microtask (console.log('p1'))start, end
7console.log('p1')Web API Timers: [timeout1, timeout2] Microtask Queue: [console.log('p2')]start, end
⏩ After exec—Web API Timers: [timeout1, timeout2] Microtask Queue: [console.log('p2')]start, end, p1
8— (Stack empty)🟢 Event Loop picks Microtask (console.log('p2'))start, end, p1
9console.log('p2')Web API Timers: [timeout1, timeout2]start, end, p1
⏩ After exec—Web API Timers: [timeout1, timeout2]start, end, p1, p2
10— (Stack empty)🟢 Event Loop picks first Macrotask (timeout1)start, end, p1, p2
11console.log('timeout1')Web API Timers: [timeout2]start, end, p1, p2
⏩ After exec—Web API Timers: [timeout2]start, end, p1, p2, timeout1
12— (Stack empty)🟢 Event Loop picks next Macrotask (timeout2)start, end, p1, p2, timeout1
13console.log('timeout2')—start, end, p1, p2, timeout1
⏩ After exec——start, end, p1, p2, timeout1, timeout2

Step-by-Step Explanation

Step 1 — console.log('start')

  • Runs synchronously.

  • Prints “start” immediately.
    ✅ Console: start

Step 2 — setTimeout(() => console.log('timeout1'))

  • Timer callback is sent to the Web API Timer queue.

  • Will move to the Macrotask queue after delay (0ms).
    ✅ Web API Timers: [timeout1]

Step 3 — Promise.resolve().then(...).then(...)

  • Creates a resolved Promise.

  • The first .then() (console.log('p1')) goes to the Microtask Queue.
    ✅ Microtask Queue: [console.log('p1')]

Step 4 — setTimeout(() => console.log('timeout2'))

  • Another timer callback is registered in the Web API Timer queue.
    ✅ Web API Timers: [timeout1, timeout2]

Step 5 — console.log('end')

  • Synchronous code continues.

  • Prints “end”.
    ✅ Console: start, end

Step 6 — Stack Empty → Event Loop picks Microtasks

  • Call Stack is now empty.

  • The Event Loop first executes all Microtasks before any Macrotasks.

Step 7 — Execute Microtask: console.log('p1')

  • Prints “p1”.

  • The .then() chained to it schedules another Microtask for “p2”.
    ✅ Microtask Queue: [console.log('p2')]
    ✅ Console: start, end, p1

Step 8 — Execute Microtask: console.log('p2')

  • Prints “p2”.
    ✅ Console: start, end, p1, p2

Step 9 — All Microtasks done → Run Macrotasks

  • The Event Loop now moves to Macrotask Queue (timers).

  • Executes the first timer: timeout1.
    ✅ Console: start, end, p1, p2, timeout1

Step 10 — Next Timer (timeout2)

  • Executes second timer.
    ✅ Final Console: start, end, p1, p2, timeout1, timeout2
async function foo() {
  console.log('foo start');
  await Promise.resolve();
  console.log('foo end');
}
Promise.resolve().then(() => console.log('promise1'));
foo();
console.log('script');

// foo start
// script
// promise1
// foo end

Execution Table

StepCall StackWeb APIs / QueuesConsole (so far)
1Promise.resolve().then(() => console.log('promise1'))Microtask Queue: [console.log('promise1')]—
2foo()Microtask Queue: [console.log('promise1')]—
3Inside foo: console.log('foo start')Microtask Queue: [console.log('promise1')]—
⏩ After exec—Microtask Queue: [console.log('promise1')]foo start
4Inside foo: await Promise.resolve()—foo start
⏩ After exec—Microtask Queue: [console.log('promise1'), console.log('foo end')]foo start
5console.log('script')Microtask Queue: [console.log('promise1'), console.log('foo end')]foo start
⏩ After exec—Microtask Queue: [console.log('promise1'), console.log('foo end')]foo start, script
6— (Stack empty)🟢 Event Loop picks Microtasksfoo start, script
7console.log('promise1')Microtask Queue: [console.log('foo end')]foo start, script
⏩ After exec—Microtask Queue: [console.log('foo end')]foo start, script, promise1
8console.log('foo end')—foo start, script, promise1
⏩ After exec——foo start, script, promise1, foo end

Step-by-Step Explanation

Step 1 — Promise.resolve().then(() => console.log('promise1'))

  • A resolved Promise is created immediately.

  • The .then() callback (console.log('promise1')) is queued in the Microtask Queue.
    ✅ Microtask Queue: [promise1]

Step 2 — foo() call

  • The async function foo() is invoked.

  • Added to the Call Stack and begins execution.

Step 3 — Inside foo: console.log('foo start')

  • Synchronous statement runs instantly.

  • Prints “foo start”.
    ✅ Console: foo start

Step 4 — Inside foo: await Promise.resolve()

  • Promise.resolve() returns a resolved Promise.

  • The rest of foo() (console.log('foo end')) is scheduled as a Microtask.
    ✅ Microtask Queue: [promise1, foo end]

Step 5 — console.log('script')

  • Global synchronous code continues.

  • Prints “script” immediately.
    ✅ Console: foo start, script

Step 6 — Stack Empty → Event Loop runs Microtasks

  • Call Stack is now empty.

  • Event Loop picks tasks from Microtask Queue in FIFO order.

Step 7 — Execute Microtask: console.log('promise1')

  • Runs first (it was queued before foo end).

  • Prints “promise1”.
    ✅ Console: foo start, script, promise1

Step 8 — Execute Microtask: console.log('foo end')

  • Resumes the paused async function foo() after await.

  • Prints “foo end”.
    ✅ Final Console: foo start, script, promise1, foo end

console.log('1');
Promise.resolve().then(() => console.log('2')).then(() => console.log('3'));
console.log('4');

// 1
// 4
// 2
// 3

Execution Table

StepCall StackWeb APIs / QueuesConsole (so far)
1console.log('1')——
⏩ After exec——1
2Promise.resolve().then(() => console.log('2')).then(() => console.log('3'))Microtask Queue: [console.log('2')]1
3console.log('4')Microtask Queue: [console.log('2')]1
⏩ After exec—Microtask Queue: [console.log('2')]1, 4
4— (Stack empty)🟢 Event Loop picks Microtask (console.log('2'))1, 4
5console.log('2')Microtask Queue: [console.log('3')]1, 4
⏩ After exec—Microtask Queue: [console.log('3')]1, 4, 2
6— (Stack empty)🟢 Event Loop picks Microtask (console.log('3'))1, 4, 2
7console.log('3')—1, 4, 2
⏩ After exec——1, 4, 2, 3

Step-by-Step Explanation

Step 1 — console.log('1')

  • Runs synchronously and prints “1” immediately.
    ✅ Console: 1

Step 2 — Promise.resolve().then(...).then(...)

  • Creates a resolved Promise instantly.

  • The first .then() callback (console.log('2')) is queued in the Microtask Queue.
    ✅ Microtask Queue: [console.log('2')]

Step 3 — console.log('4')

  • Continues synchronous execution.

  • Prints “4” immediately.
    ✅ Console: 1, 4

Step 4 — Event Loop picks Microtasks

  • Call Stack is empty, so the Event Loop starts executing Microtasks in order.

Step 5 — Execute Microtask: console.log('2')

  • Prints “2”.

  • The chained .then() schedules another Microtask (console.log('3')).
    ✅ Microtask Queue: [console.log('3')]
    ✅ Console: 1, 4, 2

Step 6 — Execute Microtask: console.log('3')

  • Runs the next Microtask and prints “3”.
    ✅ Final Console: 1, 4, 2, 3
async function test() {
  console.log('start');
  await new Promise(resolve => {
    console.log('promise executor');
    resolve();
  });
  console.log('after await');
}
test();
console.log('end');

// start
// promise executor
// end
// after await

Execution Table

StepCall StackWeb APIs / QueuesConsole (so far)
1test()——
2Inside test: console.log('start')——
⏩ After exec——start
3Inside test: await new Promise(...)—start
4Executes Promise executor → console.log('promise executor')—start
⏩ After exec—Microtask Queue: [console.log('after await')]start, promise executor
5console.log('end')Microtask Queue: [console.log('after await')]start, promise executor
⏩ After exec—Microtask Queue: [console.log('after await')]start, promise executor, end
6— (Stack empty)🟢 Event Loop picks Microtask (console.log('after await'))start, promise executor, end
7console.log('after await')—start, promise executor, end
⏩ After exec——start, promise executor, end, after await

Step-by-Step Explanation

Step 1 — Call test()

  • The async function test() is invoked.

  • Added to the Call Stack and starts executing.

Step 2 — Inside test: console.log('start')

  • Runs synchronously and prints “start”.
    ✅ Console: start

Step 3 — Inside test: await new Promise(...)

  • A new Promise is created.

  • Its executor function runs immediately.

Step 4 — Inside the Promise executor

  • Prints “promise executor”.

  • Calls resolve(), which marks the Promise as resolved.

  • The remainder of test() (console.log('after await')) is queued as a Microtask.
    ✅ Microtask Queue: [console.log('after await')]
    ✅ Console: start, promise executor

Step 5 — console.log('end')

  • After test() pauses at await, the global code continues.

  • Prints “end”.
    ✅ Console: start, promise executor, end

Step 6 — Stack Empty → Event Loop runs Microtasks

  • Call Stack is empty.

  • Event Loop checks Microtask Queue and finds console.log('after await').

Step 7 — Execute Microtask: console.log('after await')

  • Prints “after await”.
    ✅ Final Console: start, promise executor, end, after await
console.log('A');
Promise.resolve().then(() => {
  console.log('B');
  Promise.resolve().then(() => console.log('C'));
});
console.log('D');

// A
// D
// B
// C

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1console.log('A')——
⏩ After exec——A
2Promise.resolve().then(...)Microtask Queue: [then callback → console.log('B')]A
3console.log('D')Microtask Queue: [then callback → console.log('B')]A
⏩ After exec—Microtask Queue: [then callback → console.log('B')]A, D
4— (Stack empty)🟢 Event Loop executes first Microtask (console.log('B'))A, D
5Inside Microtask: console.log('B')Adds new Microtask [console.log('C')]A, D
6—Microtask Queue: [console.log('C')]A, D, B
7— (Stack empty again)🟢 Event Loop executes next Microtask (console.log('C'))A, D, B
⏩ After exec——A, D, B, C

Step-by-Step Explanation

Step 1 — console.log('A')

  • Runs synchronously and prints “A”.
    ✅ Console: A

Step 2 — Promise.resolve().then(...)

  • Creates a resolved promise.

  • The .then() callback (() => { console.log('B'); Promise.resolve().then(...); })
    is scheduled in the Microtask Queue.
    ✅ Microtask Queue: [B callback]

Step 3 — console.log('D')

  • Executes synchronously after the Promise setup.
    ✅ Console: A, D

Step 4 — Global execution done → Event Loop runs Microtasks

  • Call Stack is now empty.

  • Event Loop picks the first Microtask: the one that logs “B”.

Step 5 — Execute Microtask: console.log('B')

  • Prints “B”.

  • Inside this callback, another Promise.resolve().then(...) adds a new Microtask for “C”.
    ✅ Console: A, D, B
    ✅ Microtask Queue: [C callback]

Step 6 — Next Microtask: console.log('C')

  • Event Loop executes this second Microtask.
    ✅ Final Console: A, D, B, C
console.log('start');
setTimeout(() => console.log('timeout'));
Promise.resolve().then(() => {
  console.log('promise1');
  setTimeout(() => console.log('inner timeout'));
});
console.log('end');

// start  
// end  
// promise1  
// timeout  
// inner timeout

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1console.log('start')——
⏩ After exec——start
2setTimeout(...)Web API Timer: [console.log('timeout')]start
3Promise.resolve().then(...)Web API Timer: [console.log('timeout')]Microtask Queue: [promise1 callback]start
4console.log('end')Web API Timer: [console.log('timeout')]Microtask Queue: [promise1 callback]start
⏩ After exec—Web API Timer: [console.log('timeout')]Microtask Queue: [promise1 callback]start, end
5— (Stack empty)🟢 Event Loop executes Microtask (promise1)start, end
6console.log('promise1')Adds new timer → Web API Timer: [console.log('timeout'), console.log('inner timeout')]start, end, promise1
7— (Stack empty)🕓 Event Loop executes Macrotasks in order: first timeout, then inner timeoutstart, end, promise1
8console.log('timeout')Web API Timer: [console.log('inner timeout')]start, end, promise1, timeout
9console.log('inner timeout')—start, end, promise1, timeout, inner timeout

Step-by-Step Explanation

Step 1 — console.log('start')

  • Runs synchronously and prints “start”.
    ✅ Console: start

Step 2 — setTimeout(() => console.log('timeout'))

  • The callback is sent to the Web API Timer to run later as a macrotask.
    ✅ Web API Timer: [timeout callback]
    ✅ Console: start

Step 3 — Promise.resolve().then(...)

  • The .then() callback (() => { console.log('promise1'); setTimeout(...); })
    is queued in the Microtask Queue.
    ✅ Microtask Queue: [promise1 callback]

Step 4 — console.log('end')

  • Executes synchronously and prints “end”.
    ✅ Console: start, end

Step 5 — Event Loop runs Microtasks first

  • The Call Stack is empty → Event Loop picks the Microtask.

  • Executes console.log('promise1'), printing “promise1”.

  • Inside this callback, another setTimeout(() => console.log('inner timeout'))
    is registered → added to the Web API Timer.
    ✅ Web API Timer: [timeout, inner timeout]
    ✅ Console: start, end, promise1

Step 6 — Event Loop moves to Macrotasks

  • Microtasks done → next, the Macrotask Queue runs timers in order of registration.
  1. Executes first timer → “timeout”

  2. Executes next timer → “inner timeout”

✅ Final Console: start, end, promise1, timeout, inner timeout

async function run() {
  console.log('1');
  await Promise.resolve();
  console.log('2');
}
run();
run();
console.log('3');

// 1  
// 1  
// 3  
// 2  
// 2

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1(Function definitions loaded)——
2run() (1st call) → console.log('1')—1
3await Promise.resolve() (1st run)Microtask Queue: [resume run() → console.log('2')]1
4run() (2nd call) → console.log('1')Microtask Queue: [run1→2, run2→2]1, 1
5await Promise.resolve() (2nd run)Microtask Queue: [resume run1, resume run2]1, 1
6console.log('3')Microtask Queue: [resume run1, resume run2]1, 1, 3
7— (Stack empty)🟢 Event Loop executes Microtasks → runs run() continuations1, 1, 3
8Executes console.log('2') (from first run)Remaining Microtask: [resume run2]1, 1, 3, 2
9Executes console.log('2') (from second run)—1, 1, 3, 2, 2

Step-by-Step Explanation

Step 1 — Function definition phase

  • The async function run() is defined but not executed yet.

Step 2 — First run() call

  • Executes synchronously up to the first await.

  • Prints “1”.

  • The await Promise.resolve() pauses the function and schedules its continuation (the part after the await) into the Microtask Queue.
    ✅ Microtask Queue: [run1 continuation → console.log('2')]
    ✅ Console: 1

Step 3 — Second run() call

  • Executes independently of the first.

  • Prints another “1”.

  • Again, the await pauses execution and schedules the next part in the Microtask Queue.
    ✅ Microtask Queue: [run1→2, run2→2]
    ✅ Console: 1, 1

Step 4 — console.log('3')

  • This line is synchronous and runs immediately after both run() calls are initiated.
    ✅ Console: 1, 1, 3

Step 5 — Event Loop runs Microtasks

  • After all synchronous code is done, the Event Loop picks Microtasks in order.

  • First continuation (run1) executes → prints “2”.

  • Then second continuation (run2) executes → prints “2” again.
    ✅ Final Console: 1, 1, 3, 2, 2

async function run() {
  console.log('run');
  return Promise.resolve('done');
}
run().then(res => console.log(res));
console.log('after');

// run  
// after  
// done

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1(Function definition loaded)——
2run() → console.log('run')—run
3return Promise.resolve('done')Microtask Queue: [then callback → console.log(res)]run
4console.log('after')Microtask Queue: [then callback → console.log(res)]run, after
5— (Stack empty)🟢 Event Loop executes Microtaskrun, after
6Executes .then(res => console.log(res))—run, after, done

Step-by-Step Explanation

Step 1 — Function definition

  • The async function run() is defined but not yet executed.

Step 2 — Call run()

  • The function run() executes immediately.

  • Prints “run”.

  • Returns a resolved Promise with the value 'done'.

  • Since run() is async, it automatically wraps the returned value in a Promise.
    ✅ Console: run
    ✅ Microtask Queue: [.then() callback waiting for 'done']

Step 3 — console.log('after')

  • Executes synchronously right after calling run().
    ✅ Console: run, after

Step 4 — Event Loop phase

  • The Call Stack is now empty, so the Event Loop moves to the Microtask Queue.

  • It executes the .then() callback attached to the resolved Promise.

  • The callback prints “done”.

✅ Final Console Output: run, after, done

console.log('start');
Promise.resolve().then(() => console.log('p1'));
setTimeout(() => console.log('timeout'), 0);
Promise.resolve().then(() => console.log('p2'));
console.log('end');

// start  
// end  
// p1  
// p2  
// timeout

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1console.log('start')——
⏩ After exec——start
2Promise.resolve().then(() => console.log('p1'))Microtask Queue: [p1]start
3setTimeout(() => console.log('timeout'), 0)Web API Timer: [timeout]start
4Promise.resolve().then(() => console.log('p2'))Web API Timer: [timeout]Microtask Queue: [p1, p2]start
5console.log('end')Web API Timer: [timeout]Microtask Queue: [p1, p2]start
⏩ After exec—Web API Timer: [timeout]Microtask Queue: [p1, p2]start, end
6— (Stack empty)🟢 Event Loop executes Microtasks (p1, then p2)start, end
7console.log('p1')Web API Timer: [timeout]Microtask Queue: [p2]start, end, p1
8console.log('p2')Web API Timer: [timeout]start, end, p1, p2
9— (Stack empty again)🕓 Event Loop executes Macrotask → timeoutstart, end, p1, p2
10console.log('timeout')—start, end, p1, p2, timeout

Step-by-Step Explanation

Step 1 — console.log('start')

  • Runs synchronously and prints “start”.
    ✅ Console: start

Step 2 — Promise.resolve().then(() => console.log('p1'))

  • A resolved Promise immediately schedules its .then() callback in the Microtask Queue.
    ✅ Microtask Queue: [p1]

Step 3 — setTimeout(..., 0)

  • The callback is sent to the Web API Timer to be executed later as a macrotask.
    ✅ Web API Timer: [timeout]

Step 4 — Second Promise (p2)

  • Another resolved Promise adds its .then() callback to the Microtask Queue after p1.
    ✅ Microtask Queue: [p1, p2]

Step 5 — console.log('end')

  • Runs synchronously and prints “end”.
    ✅ Console: start, end

Step 6 — Event Loop runs Microtasks first

  • The Call Stack is empty, so the Event Loop executes all Microtasks in order.
  1. Runs p1 → prints “p1”

  2. Runs p2 → prints “p2”
    ✅ Console: start, end, p1, p2

Step 7 — Event Loop moves to Macrotasks

  • After all Microtasks are done, the Event Loop picks up the Macrotask from the timer queue.

  • Executes console.log('timeout'), printing “timeout”.
    ✅ Final Console: start, end, p1, p2, timeout

async function one() {
  console.log('1');
  await two();
  console.log('2');
}
async function two() {
  console.log('3');
  await null;
  console.log('4');
}
console.log('start');
one();
console.log('end');

// start  
// 1  
// 3  
// end  
// 4  
// 2

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1(Functions defined)——
2console.log('start')——
⏩ After exec——start
3one()—start
4Inside one(): console.log('1')—start, 1
5await two()—start, 1
6Inside two(): console.log('3')—start, 1, 3
7await null (in two)Microtask Queue: [resume two → console.log('4')]start, 1, 3
8one() paused (waiting for two() to finish)Microtask Queue: [resume two → console.log('4')]start, 1, 3
9console.log('end')Microtask Queue: [resume two → console.log('4')]start, 1, 3, end
10— (Stack empty)🟢 Event Loop executes Microtask: console.log('4')start, 1, 3, end
11After two() finishes → resumes one()Microtask Queue: [resume one → console.log('2')]start, 1, 3, end, 4
12🟢 Event Loop executes next Microtask: console.log('2')—start, 1, 3, end, 4, 2

Step-by-Step Explanation

Step 1 — Function definitions

  • one() and two() are defined but not executed yet.

Step 2 — console.log('start')

  • Runs synchronously and prints “start”.
    ✅ Console: start

Step 3 — Call one()

  • Enters the async function one().

  • Prints “1”.
    ✅ Console: start, 1

Step 4 — await two()

  • Before pausing, it calls two().

Step 5 — Inside two()

  • Prints “3” immediately.
    ✅ Console: start, 1, 3

  • Encounters await null, which pauses two() and schedules continuation (console.log('4')) in the Microtask Queue.
    ✅ Microtask Queue: [two continuation → console.log('4')]

Step 6 — Back to one()

  • one() now pauses (waiting for two()’s result).
    ✅ Microtask Queue: [two continuation]

Step 7 — console.log('end')

  • Runs synchronously after one() is paused.
    ✅ Console: start, 1, 3, end

Step 8 — Event Loop → Run Microtasks

  • First microtask resumes two() → prints “4”.
    ✅ Console: start, 1, 3, end, 4

  • Once two() finishes, its returned Promise resolves, so one()’s await two() continues.
    ✅ New Microtask: [one continuation → console.log('2')]

Step 9 — Run next Microtask

  • Resumes one() after await two().

  • Prints “2”.
    ✅ Console: start, 1, 3, end, 4, 2

async function foo() {
  console.log('foo start');
  await Promise.resolve();
  console.log('foo mid');
  await Promise.resolve();
  console.log('foo end');
}
console.log('script');
foo();
console.log('after');

// script  
// foo start  
// after  
// foo mid  
// foo end

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1(Function defined)——
2console.log('script')——
⏩ After exec——script
3foo()—script
4Inside foo: console.log('foo start')—script, foo start
5await Promise.resolve() (1st await)Microtask Queue: [resume foo → console.log('foo mid')]script, foo start
6console.log('after')Microtask Queue: [resume foo → console.log('foo mid')]script, foo start, after
7— (Stack empty)🟢 Event Loop runs Microtask (resume foo → console.log('foo mid'))script, foo start, after
8Inside resumed foo: console.log('foo mid')Schedules next continuation → [resume foo → console.log('foo end')]script, foo start, after, foo mid
9— (Stack empty again)🟢 Event Loop runs next Microtask (resume foo → console.log('foo end'))script, foo start, after, foo mid
10console.log('foo end')—script, foo start, after, foo mid, foo end

Step-by-Step Explanation

Step 1 — Function definition

  • async function foo() is declared but not executed yet.

Step 2 — console.log('script')

  • Runs synchronously and prints “script”.
    ✅ Console: script

Step 3 — Call foo()

  • Execution enters the foo() function.

  • Prints “foo start” synchronously.
    ✅ Console: script, foo start

Step 4 — First await Promise.resolve()

  • The Promise is already resolved, so the continuation (next line after the await)
    is scheduled in the Microtask Queue.
    ✅ Microtask Queue: [resume foo → console.log('foo mid')]

Step 5 — console.log('after')

  • The synchronous part of the script continues.

  • Prints “after”.
    ✅ Console: script, foo start, after

Step 6 — Event Loop runs Microtask

  • The Call Stack is now empty.

  • The Event Loop runs the first microtask, resuming foo() after the first await.

  • Prints “foo mid”.
    ✅ Console: script, foo start, after, foo mid

Step 7 — Second await Promise.resolve()

  • Again, the Promise is already resolved.

  • The next part (console.log('foo end')) is queued as a new Microtask.
    ✅ Microtask Queue: [resume foo → console.log('foo end')]

Step 8 — Run next Microtask

  • Event Loop picks the next microtask, resuming foo() again.

  • Prints “foo end”.
    ✅ Console: script, foo start, after, foo mid, foo end

Promise.resolve().then(() => {
  console.log('p1');
  return Promise.resolve();
}).then(() => {
  console.log('p2');
  return Promise.resolve();
}).then(() => console.log('p3'));

console.log('script');

// script  
// p1  
// p2  
// p3

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1(Promise chain registered)——
2console.log('script')—script
3(Stack empty → microtasks run)Microtask Queue: [then → console.log('p1')]script
4console.log('p1') executes → schedules next .then()Microtask Queue: [then → console.log('p2')]script, p1
5Event Loop runs next microtask → console.log('p2')Microtask Queue: [then → console.log('p3')]script, p1, p2
6Event Loop runs next microtask → console.log('p3')—script, p1, p2, p3

Step-by-Step Explanation

Step 1 — Promise chain registration

  • The Promise.resolve() chain is created.

  • All .then() callbacks are stored to run after the current synchronous code finishes.

  • No output yet.

Step 2 — console.log('script')

  • Runs synchronously.

  • Prints “script”.
    ✅ Console: script

Step 3 — Microtask phase begins

  • Main thread is now free.

  • Event loop starts processing microtasks (promise callbacks).

Step 4 — First .then() runs

  • Executes console.log('p1').
    ✅ Console: script, p1

  • The .then() returns another resolved Promise.

  • This queues the next .then() → console.log('p2').

Step 5 — Second .then() runs

  • Executes console.log('p2').
    ✅ Console: script, p1, p2

  • Again returns a resolved Promise → queues next .then() → console.log('p3').

Step 6 — Third .then() runs

  • Executes console.log('p3').
    ✅ Console: script, p1, p2, p3
async function first() {
  console.log('1');
  await second();
  console.log('2');
}
async function second() {
  console.log('3');
  await Promise.resolve();
  console.log('4');
}
setTimeout(() => console.log('5'));
first();
console.log('6');

// 1  
// 3  
// 6  
// 4  
// 2  
// 5

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1(register functions + setTimeout callback)Macrotask Queue: [timeout → 5]—
2first()——
3console.log('1')—1
4second()——
5console.log('3')—1, 3
6await Promise.resolve() → pauses second()Microtask Queue: resume second()1, 3
7console.log('6')—1, 3, 6
8Microtask: resume second() → console.log('4')—1, 3, 6, 4
9Microtask: resume first() → console.log('2')—1, 3, 6, 4, 2
10Macrotask: setTimeout → console.log('5')—1, 3, 6, 4, 2, 5

Step-by-Step Explanation

Step 1 — Setup phase

  • The two async functions are defined.

  • setTimeout(() => console.log('5')) is scheduled.

  • Its callback goes into the Macrotask Queue.

  • No output yet.

Step 2 — first() is called

  • Enters call stack.

Step 3 — Inside first(): console.log('1')

  • Prints 1.
    ✅Console: 1

Step 4 — Inside first(): await second()

  • Calls second().

  • Execution enters second().

Step 5 — Inside second(): console.log('3')

  • Prints 3.
    ✅ Console: 1, 3

Step 6 — Inside second(): await Promise.resolve()

  • The await pauses second() here.

  • A microtask is scheduled to resume second().

Step 7 — Back to main script: console.log('6')

  • Since async functions paused, synchronous code continues.

  • Prints 6.
    ✅ Console: 1, 3, 6

Step 8 — Microtask: resume second()

  • Runs the rest of second().

  • Prints 4.
    ✅ Console: 1, 3, 6, 4

  • After finishing second(), the awaiting part of first() is now queued as a microtask.

Step 9 — Microtask: resume first()

  • Executes the remaining lines of first().

  • Prints 2.
    ✅ Console: 1, 3, 6, 4, 2

Step 10 — Macrotask Queue runs

  • setTimeout callback finally executes.

  • Prints 5.
    ✅ Console: 1, 3, 6, 4, 2, 5

console.log('start');
Promise.resolve().then(() => {
  console.log('p1');
  queueMicrotask(() => console.log('qm1'));
});
queueMicrotask(() => console.log('qm0'));
console.log('end');

// start
// end
// p1
// qm0
// qm1

Execution Table

StepCall StackWeb APIs / QueuesConsole
1console.log('start')——
⏩ After exec——start
2Promise.resolve().then()Microtask Queue: [p1 → qm1]start
3queueMicrotask(qm0)Microtask Queue: [p1 → qm1, qm0]start
4console.log('end')Microtask Queue: [p1 → qm1, qm0]start
⏩ After exec—Microtask Queue: [p1 → qm1, qm0]start, end
5Microtask: p1Microtask Queue: [qm1, qm0]start, end
6Microtask: qm0Microtask Queue: [qm1]start, end, p1
7Microtask: qm1—p1, qm0

Step-by-Step Explanation

Step 1 — console.log('start')

  • Synchronous.

  • Runs immediately.

  • Prints start.

✅ Console: start

Step 2 — Promise.resolve().then(...)

  • The .then() callback is scheduled into the Microtask Queue.

  • Inside it, queueMicrotask(qm1) is also scheduled but will only be queued after p1 runs, not now.

Step 3 — queueMicrotask(qm0)

  • This microtask (qm0) is added directly to the Microtask Queue.

  • Queue order now: p1 → qm1 (pending inside p1), qm0.

Step 4 — console.log('end')

  • Synchronous.

  • Executes immediately.

✅ Console: start, end

Step 5 — Microtask: p1

  • Runs first microtask.

  • Prints p1.

  • While running, it schedules another microtask: qm1 (queued at the end).

Queue now: qm0 → qm1

Step 6 — Microtask: qm0

  • Runs next.

  • Prints qm0.

Step 7 — Microtask: qm1

  • Runs last.

  • Prints qm1.

async function a() {
  console.log('a1');
  await Promise.resolve();
  console.log('a2');
}
async function b() {
  console.log('b1');
  await null;
  console.log('b2');
}
a();
b();
console.log('sync');

// a1
// b1
// sync
// a2
// b2

Execution table

StepCall StackWeb APIs / QueuesConsole
1a() → console.log('a1')—a1
2await Promise.resolve()Microtask Queue: [a2]a1
3b() → console.log('b1')Microtask Queue: [a2]a1, b1
4await nullMicrotask Queue: [a2, b2]a1, b1
5console.log('sync')Microtask Queue: [a2, b2]a1, b1, sync
6Microtask: a2Microtask Queue: [b2]a1, b1, sync
7Microtask: b2—a1, b1, sync

Step-by-Step Explanation

Step 1 — a() starts

  • a1 is printed.

  • await Promise.resolve() queues the continuation (a2) into the microtask queue.

Step 2 — b() starts

  • b1 is printed.

  • await null also queues its continuation (b2) into the microtask queue.

Step 3 — console.log('sync')

  • Synchronous.

  • Executes immediately.

Step 4 — Microtask: continuation of a()

  • Runs console.log('a2').

Step 5 — Microtask: continuation of b()

  • Runs console.log('b2').
console.log('s');
setTimeout(() => console.log('t1'), 0);
Promise.resolve().then(() => {
  console.log('p1');
  setTimeout(() => console.log('t2'), 0);
});
console.log('e');

// s
// e
// p1
// t1
// t2

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1console.log('s')—s
2setTimeout(t1)Web API Timer: [t1]s
3Promise .then() registeredMicrotask Queue: [p1 → schedule t2]s
4console.log('e')Microtask Queue: [p1 → schedule t2]s, e
5Microtask runs: p1Web API Timer: [t1, t2]s, e, p1
6Macrotask: t1 runsWeb API Timer: [t2]s, e, p1, t1
7Macrotask: t2 runs—s, e, p1, t1, t2

Step-by-Step Explanation

Step 1 — console.log('s')

  • The first synchronous line runs.

  • It prints "s" to the console.

  • The call stack becomes empty after printing.

Console: s

Step 2 — setTimeout(t1)

  • setTimeout is added to the call stack.

  • Its callback t1 is moved to the Web API Timer.

  • It will later enter the macrotask queue.

Console: s

Step 3 — Promise .then() registered

  • The .then() callback is placed into the microtask queue.

  • It will run after all synchronous code finishes.

Console: s

Step 4 — console.log('e')

  • Synchronous code prints "e".

  • After this step, the call stack becomes empty and microtasks can start.

Console: s, e

Step 5 — Microtask: p1

  • The microtask callback runs and prints "p1".

  • Inside it, another setTimeout schedules t2 in the Web API Timer.

Console: s, e, p1

Step 6 — Macrotask: t1

  • The event loop moves to macrotasks.

  • t1 executes and prints "t1".

Console: s, e, p1, t1

Step 7 — Macrotask: t2

  • The next macrotask, t2, executes and prints "t2".

Console: s, e, p1, t1, t2

async function f() {
  console.log('f start');
  await Promise.resolve().then(() => console.log('inner'));
  console.log('f end');
}
f();
Promise.resolve().then(() => console.log('p after'));

// f start
// inner
// p after
// f end

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1f() → console.log('f start')—f start
2await Promise.resolve().then(inner)Microtask Queue: [inner, f end]f start
3Promise .then(p after) registeredMicrotask Queue: [inner, f end, p after]f start
4Microtask runs: innerMicrotask Queue: [f end, p after]f start, inner
5Microtask runs: continuation of f() → console.log('f end')Microtask Queue: [p after]f start, inner, f end
6Microtask runs: p after—f start, inner, f end, p after

Step-by-Step Explanation

Step 1 — f() starts

  • The async function f is called.

  • It prints "f start".

  • Execution reaches the await.

Console: f start

Step 2 — await Promise.resolve().then(inner)

  • The .then(() => console.log('inner')) schedules "inner" as a microtask.

  • The continuation of f() (which prints "f end") is also queued as a microtask.

Console: f start

Step 3 — Independent Promise .then(p after)

  • Another .then() registers "p after" as a microtask.

  • It is added after the already queued microtasks.

Console: f start

Step 4 — Microtask: inner

  • The first microtask runs.

  • Prints "inner".

Console: f start, inner

Step 5 — Microtask: continuation of f() → f end

  • The continuation of the async function runs.

  • Prints "f end".

Console: f start, inner, f end

Step 6 — Microtask: p after

  • The final microtask runs.

  • Prints "p after".

Console: f start, inner, f end, p after

console.log('1');
Promise.resolve().then(() => console.log('2'));
Promise.resolve().then(() => {
  console.log('3');
  return Promise.resolve().then(() => console.log('4'));
});
console.log('5');

// 1
// 5
// 2
// 3
// 4

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1console.log('1')—1
2First Promise .then(2) registeredMicrotask Queue: [2]1
3Second Promise .then(3 → then 4) registeredMicrotask Queue: [2, 3→4]1
4console.log('5')Microtask Queue: [2, 3→4]1, 5
5Microtask runs: 2Microtask Queue: [3→4]1, 5, 2
6Microtask runs: 3 → schedules next microtask 4Microtask Queue: [4]1, 5, 2, 3
7Microtask runs: 4—1, 5, 2, 3, 4

Step-by-Step Explanation

Step 1 — console.log('1')

  • Synchronous line runs immediately.

  • Prints 1.

Console: 1

Step 2 — First Promise .then(() => console.log('2'))

  • Registers a microtask for printing 2.

  • It will run after all synchronous code completes.

Console: 1

Step 3 — Second Promise .then(...)

  • Registers the microtask that prints 3.

  • Inside its callback, it returns another resolved promise which will later schedule 4.

Console: 1

Step 4 — console.log('5')

  • Synchronous.

  • Prints 5.

Console: 1, 5

Step 5 — Microtask: print 2

  • First microtask runs.

  • Prints 2.

Console: 1, 5, 2

Step 6 — Microtask: print 3 and schedule 4

  • Prints 3.

  • The returned promise queues another microtask for 4.

Console: 1, 5, 2, 3

Step 7 — Microtask: print 4

  • Final microtask runs.

  • Prints 4.

Console: 1, 5, 2, 3, 4

setTimeout(() => console.log('t'), 0);
queueMicrotask(() => console.log('qm'));
Promise.resolve().then(() => console.log('p'));
console.log('s');

// s
// qm
// p
// t

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1(register callbacks)Macrotask: [setTimeout → t] • Microtask: [queueMicrotask → qm], [promise.then → p]—
2console.log('s')—s
3(stack empty → microtasks run)Microtask Queue: [qm, p]s
4queueMicrotask executes → console.log('qm')Microtask Queue: [p]s, qm
5promise.then executes → console.log('p')—s, qm, p
6Macrotask executes → setTimeout → console.log('t')—s, qm, p, t

Step-by-Step Explanation

Step 1 — Setup phase

  • setTimeout is registered → its callback goes to the Macrotask Queue.

  • queueMicrotask registers qm in the Microtask Queue.

  • Promise.resolve().then() registers p in the Microtask Queue.

Step 2 — console.log('s')

  • Synchronous code runs first.
    Console: s

Step 3 — Microtask phase begins

  • Call stack is empty → event loop starts running microtasks.

  • Current microtask queue order: qm → p.

Step 4 — Microtask: queueMicrotask runs

  • Executes console.log('qm').
    Console: s, qm

Step 5 — Microtask: promise.then runs

  • Executes console.log('p').
    Console: s, qm, p

Step 6 — Macrotask phase

  • The setTimeout callback runs now.

  • Executes console.log('t').
    Console: s, qm, p, t

(async () => {
  console.log('I');
  await 0;
  console.log('II');
})();
Promise.resolve().then(() => console.log('P'));
console.log('S');

// I
// S
// II
// P

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1(register async IIFE + promise.then)Microtask Queue: [resume async IIFE → II, promise.then → P]—
2console.log('I')—I
3await 0 → async IIFE pausesMicrotask Queue: [resume IIFE → II, promise.then → P]I
4console.log('S')—I, S
5Microtask: resume async IIFE → console.log('II')Microtask Queue: [promise.then → P]I, S, II
6Microtask: promise.then → console.log('P')—I, S, II, P

Step-by-Step Explanation

Step 1 — Setup phase

  • The async IIFE is created and immediately scheduled to run.

  • Promise.resolve().then registers a microtask for printing P.

Step 2 — Inside IIFE: console.log('I')

  • First synchronous line inside the async function executes.
    Console: I

Step 3 — await 0

await 0 immediately resolves.
The async function pauses, and a microtask is queued to resume it later.
Console: I

Step 4 — console.log('S')

Back to main script → synchronous code continues.
Console: I, S

Step 5 — Microtask: resume async IIFE

Async function continues and executes console.log('II').
Console: I, S, II

Step 6 — Microtask: Promise.then

Executes console.log('P').
Console: I, S, II, P

console.log('start');
Promise.resolve().then(() => console.log('p1')).then(() => console.log('p2'));
(async () => {
  await null;
  console.log('after await');
})();
console.log('end');

// start
// end
// p1
// after await
// p2

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1console.log('start')—start
2Promise.resolve().then(...)Microtask queued: p1start
3(async IIFE) call—start
4await null suspends asyncMicrotask queued: resume → after awaitstart
5console.log('end')Microtasks: p1, then p2, then after awaitstart, end
6(microtask) p1Microtask queued: p2start, end, p1
7(microtask) p2—start, end, p1, p2
8(microtask) after await—start, end, p1, p2, after await

Step-by-Step Explanation

Step 1 — console.log('start')

  • Runs immediately.

  • Prints start.

  • No tasks scheduled.

✅ Console: start

Step 2 — Promise.resolve().then(() => console.log('p1'))

  • The .then() registers a microtask.

  • p1 is added to the Microtask Queue.

Step 3 — Async IIFE runs

(async () => { ... })() is called synchronously.

Step 4 — Inside async: await null

  • await null pauses the function.

  • Schedules a microtask to resume the async function.

  • That microtask will later run console.log('after await').

Step 5 — console.log('end')

  • Last synchronous line.

  • Prints end.

✅ Console: start, end

Step 6 — Event Loop → Run Microtasks

Microtasks run in order:

Step 7 — Microtask: p1

  • console.log('p1') runs.

  • Its .then(() => console.log('p2')) schedules another microtask p2.

✅ Console: start, end, p1

Step 8 — Microtask: p2

  • Prints p2.

✅ Console: start, end, p1, p2

Step 9 — Microtask: after await

  • Async function resumes.

  • Prints after await.

✅ Final Console:
start, end, p1, p2, after await

async function a() {
  console.log('A1');
  await Promise.resolve();
  console.log('A2');
}
console.log('start');
a();
Promise.resolve().then(() => console.log('P1'));
queueMicrotask(() => console.log('QM1'));
console.log('end');

// start
// A1
// end
// A2
// P1
// QM1

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1console.log('start')—start
2a()—start
3Inside a: console.log('A1')—start, A1
4Inside a: await Promise.resolve()Microtask: resume a() → A2start, A1
5Promise.resolve().then(... )Microtask queued: P1start, A1
6queueMicrotask(...)Microtask queued: QM1start, A1
7console.log('end')Microtasks pending: A2, P1, QM1start, A1, end
8(microtask) resume async → A2Remaining: P1, QM1start, A1, end, A2
9(microtask) P1Remaining: QM1start, A1, end, A2, P1
10(microtask) QM1—start, A1, end, A2, P1, QM1

Step-by-Step Explanation

Step 1 — console.log('start')

  • Runs immediately.

  • Prints start.

✅ Console: start

Step 2 — a()

  • Async function a() is called.

  • Execution enters the function.

Step 3 — Inside a: console.log('A1')

  • Runs synchronously.

  • Prints A1.

✅ Console: start, A1

Step 4 — await Promise.resolve()

  • Execution inside a() pauses.

  • The continuation (console.log('A2')) is added to the Microtask Queue.

Step 5 — Promise.resolve().then(() => console.log('P1'))

  • Schedules microtask P1.

Step 6 — queueMicrotask(() => console.log('QM1'))

  • Schedules microtask QM1.

Step 7 — console.log('end')

  • Runs synchronously.

  • Prints end.

✅ Console: start, A1, end

Step 8 — Microtask: resume a() → console.log('A2')

  • Async function continues after await.

  • Prints A2.

✅ Console: start, A1, end, A2

Step 9 — Microtask: P1

  • Runs next.

  • Prints P1.

✅ Console: start, A1, end, A2, P1

Step 10 — Microtask: QM1

  • Final microtask prints QM1.

✅ Final Console: start, A1, end, A2, P1, QM1

console.log('s');
Promise.resolve().then(() => {
  console.log('p1');
  queueMicrotask(() => console.log('qm1'));
}).then(() => console.log('p2'));
console.log('e');

// s
// e
// p1
// qm1
// p2

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1console.log('s')—s
2Promise.resolve().then(...)Microtask queued: p1s
3console.log('e')Microtasks pending: p1s, e
4(microtask) run p1queueMicrotask: qm1 addeds, e, p1
5After p1 resolves → .then(() => console.log('p2'))Microtask queued: p2s, e, p1
6(microtask) run p2Remaining: qm1s, e, p1, p2
7(microtask) run qm1—s, e, p1, p2, qm1

Step-by-Step Explanation

Step 1 — console.log('s')

  • Runs immediately.

  • Prints s.

✅ Console: s

Step 2 — Promise.resolve().then(...)

  • .then() registers a microtask that will print p1.

  • Microtask p1 is queued.

Step 3 — console.log('e')

  • Executes synchronously.

  • Prints e.

✅ Console: s, e

Step 4 — Microtask: run p1

  • Microtask prints p1.

  • Inside p1, queueMicrotask(() => console.log('qm1')) schedules qm1.

✅ Console: s, e, p1

Step 5 — Chain .then(() => console.log('p2'))

  • After p1 finishes, its .then() schedules another microtask: p2.

Step 6 — Microtask: run p2

  • Prints p2.

✅ Console: s, e, p1, p2

Step 7 — Microtask: run qm1

  • Final microtask prints qm1.

✅ Final Console: s, e, p1, p2, qm1

async function x() {
  console.log('x1');
  await new Promise(res => res());
  console.log('x2');
}
x();
Promise.resolve().then(() => console.log('p'));
console.log('sync');

// x1
// sync
// x2
// p

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1x()——
2Inside x: console.log('x1')—x1
3Inside x: await new Promise(res => res())Microtask queued: resume x() → run x2x1
4Promise.resolve().then(...)Microtask queued: px1
5console.log('sync')Microtasks pending: x2, px1, sync
6(microtask) resume async → x2Remaining: px1, sync, x2
7(microtask) p—x1, sync, x2, p

Step-by-Step Explanation

Step 1 — x()

  • Async function x() is called.

  • Execution enters the function.

Step 2 — Inside x: console.log('x1')

  • Runs immediately.

  • Prints x1.

✅ Console: x1

Step 3 — await new Promise(res => res())

  • new Promise(res => res()) resolves instantly.

  • await pauses x() and schedules a microtask that will later run console.log('x2').

Step 4 — Promise.resolve().then(() => console.log('p'))

  • Schedules microtask p.

Step 5 — console.log('sync')

  • Runs synchronously.

  • Prints sync.

✅ Console: x1, sync

Step 6 — Microtask: resume async → console.log('x2')

  • x() continues after await.

  • Prints x2.

✅ Console: x1, sync, x2

Step 7 — Microtask: p

  • Runs next.

  • Prints p.

✅ Final Console: x1, sync, x2, p

console.log('start');
Promise.resolve().then(() => {
  console.log('p1');
  return Promise.resolve();
}).then(() => {
  console.log('p2');
});
setTimeout(() => console.log('t'), 0);
console.log('end');

// start
// end
// p1
// p2
// t

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1console.log('start')—start
2Promise.resolve().then(...)Microtask queued: p1start
3setTimeout(..., 0)Macrotask queued: tstart
4console.log('end')Microtasks pending: p1start, end
5(microtask) run p1Microtask queued: p2start, end, p1
6(microtask) run p2—start, end, p1, p2
7(macrotask) run t—start, end, p1, p2, t

Step-by-Step Explanation

Step 1 — console.log('start')

  • Executes immediately.

  • Prints start.

✅ Console: start

Step 2 — Promise.resolve().then(...)

  • .then() schedules a microtask that will run p1.

Step 3 — setTimeout(() => console.log('t'), 0)

  • Adds t to the macrotask (callback) queue.

Step 4 — console.log('end')

  • Executes synchronously.

  • Prints end.

✅ Console: start, end

Step 5 — Microtask: run p1

  • Prints p1.

  • The return Promise.resolve() triggers another .then() which schedules a microtask p2.

✅ Console: start, end, p1

Step 6 — Microtask: run p2

  • Prints p2.

✅ Console: start, end, p1, p2

Step 7 — Macrotask: run t

  • Event loop moves to macrotasks.

  • Prints t.

✅ Final Console: start, end, p1, p2, t

(async function() {
  console.log('A');
  await Promise.resolve();
  console.log('B');
  await null;
  console.log('C');
})();
console.log('D');

// A
// D
// B
// C

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1(async IIFE) starts——
2console.log('A')—A
3await Promise.resolve()Microtask queued: resume → BA
4console.log('D')Microtasks pending: BA, D
5(microtask) resume async → console.log('B')Microtask queued: continue → C (from await null)A, D, B
6(microtask) resume async → console.log('C')—A, D, B, C

Step-by-Step Explanation

Step 1 — Async IIFE begins

  • The immediately invoked async function starts executing.

Step 2 — console.log('A')

  • Executes synchronously.

  • Prints A.

✅ Console: A

Step 3 — await Promise.resolve()

  • Promise.resolve() resolves immediately.

  • await pauses the function.

  • Schedules a microtask to resume the async function and run B.

Step 4 — console.log('D')

  • Synchronous continuation outside the async function.

  • Prints D.

✅ Console: A, D

Step 5 — Microtask: resume → console.log('B')

  • Async function continues after the first await.

  • Prints B.

  • The next line is await null, which again pauses and schedules another microtask to continue with C.

✅ Console: A, D, B

Step 6 — Microtask: resume → console.log('C')

  • Async function resumes after await null.

  • Prints C.

✅ Final Console: A, D, B, C

console.log('start');
Promise.resolve().then(() => console.log('p1'));
queueMicrotask(() => console.log('qm'));
(async () => console.log('iife'))();
console.log('end');

// start
// iife
// end
// p1
// qm

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1console.log('start')—start
2Promise.resolve().then(...)Microtask queued: p1start
3queueMicrotask(...)Microtask queued: qmstart
4(async IIFE) call—start
5Inside IIFE: console.log('iife')—start, iife
6console.log('end')Microtasks pending: p1, qmstart, iife, end
7(microtask) p1Remaining: qmstart, iife, end, p1
8(microtask) qm—start, iife, end, p1, qm

Step-by-Step Explanation

Step 1 — console.log('start')

  • Runs immediately.

  • Prints start.

✅ Console: start

Step 2 — Promise.resolve().then(() => console.log('p1'))

  • Schedules microtask p1.

Step 3 — queueMicrotask(() => console.log('qm'))

  • Schedules microtask qm.

Step 4 — (async () => console.log('iife'))()

  • Async IIFE is called synchronously.

Step 5 — Inside async IIFE: console.log('iife')

  • Executes synchronously.

  • Prints iife.

✅ Console: start, iife

Step 6 — console.log('end')

  • Executes synchronously.

  • Prints end.

✅ Console: start, iife, end

Step 7 — Microtask: p1

  • First microtask runs.

  • Prints p1.

✅ Console: start, iife, end, p1

Step 8 — Microtask: qm

  • Second microtask runs.

  • Prints qm.

✅ Final Console: start, iife, end, p1, qm

let p = Promise.resolve();
p.then(() => {
  console.log('then1');
  p.then(() => console.log('then1.1'));
});
p.then(() => console.log('then2'));
console.log('sync');

// sync
// then1
// then2
// then1.1

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1console.log('sync')Microtasks pending: then1, then2 (from p.then)sync
2(microtask) run then1New microtask added: then1.1sync, then1
3(microtask) run then2—sync, then1, then2
4(microtask) run then1.1—sync, then1, then2, then1.1

Step-by-Step Explanation

Step 1 — console.log('sync')

  • This is the only synchronous operation.

  • Prints sync.

✅ Console: sync

Step 2 — Microtask: run then1

  • Runs the first microtask created by p.then(...).

  • Prints then1.

  • Inside then1, we call:

p.then(() => console.log('then1.1'));
  • Since p is already resolved, this immediately queues another microtask: then1.1.

✅ Console: sync, then1

Step 3 — Microtask: run then2

  • Runs the second microtask from the original code.

  • Prints then2.

✅ Console: sync, then1, then2

Step 4 — Microtask: run then1.1

  • Runs last, because it was queued during execution of then1.

  • Prints then1.1.

✅ Final Console: sync, then1, then2, then1.1

console.log('A');
setTimeout(() => console.log('timeout'), 0);
Promise.resolve().then(() => console.log('promise'));
queueMicrotask(() => console.log('micro'));
console.log('B');

// A
// B
// promise
// micro
// timeout

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1console.log('A')—A
2setTimeout(...)Macrotask queued: timeoutA
3Promise.resolve().then(...)Microtask queued: promiseA
4queueMicrotask(...)Microtask queued: micro (after promise)A
5console.log('B')Microtasks pending: promise, microA, B
6(microtask) run promiseRemaining: microA, B, promise
7(microtask) run micro—A, B, promise, micro
8(macrotask) run timeout—A, B, promise, micro, timeout

Step-by-Step Explanation

Step 1 — console.log('A')

  • Runs immediately.

  • Prints A.

✅ Console: A

Step 2 — setTimeout(() => console.log('timeout'), 0)

  • Adds timeout to the macrotask queue.

Step 3 — Promise.resolve().then(() => console.log('promise'))

  • Adds promise to the microtask queue.

Step 4 — queueMicrotask(() => console.log('micro'))

  • Adds micro to the microtask queue, queued after promise.

Step 5 — console.log('B')

  • Runs synchronously.

  • Prints B.

✅ Console: A, B

Step 6 — Microtask: run promise

  • Prints promise.

✅ Console: A, B, promise

Step 7 — Microtask: run micro

  • Prints micro.

✅ Console: A, B, promise, micro

Step 8 — Macrotask: run timeout

  • Prints timeout.

✅ Final Console: A, B, promise, micro, timeout

async function outer() {
  console.log('o1');
  await inner();
  console.log('o2');
}
async function inner() {
  console.log('i1');
}
outer();
Promise.resolve().then(() => console.log('p'));
console.log('sync');

// o1
// i1
// sync
// o2
// p

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1outer()——
2Inside outer: console.log('o1')—o1
3Inside outer: await inner()Microtask: resume outer() → run o2o1
4inner()—o1
5Inside inner: console.log('i1')—o1, i1
6Promise.resolve().then(...)Microtask queued: po1, i1
7console.log('sync')Microtasks pending: resume outer (o2), po1, i1, sync
8(microtask) resume async outer() → o2Remaining: po1, i1, sync, o2
9(microtask) run p—o1, i1, sync, o2, p

Step-by-Step Explanation

Step 1 — outer()

  • Async function outer() is called.

  • Execution enters the function.

Step 2 — Inside outer: console.log('o1')

  • Runs synchronously.

  • Prints o1.

✅ Console: o1

Step 3 — await inner()

  • inner() is called.

  • outer() pauses at the await, scheduling a microtask to resume it later.

Step 4 — inner()

  • Async function inner() starts executing.

Step 5 — Inside inner: console.log('i1')

  • Runs synchronously.

  • Prints i1.

✅ Console: o1, i1

Step 6 — Promise.resolve().then(() => console.log('p'))

  • Schedules microtask p.

Step 7 — console.log('sync')

  • Runs synchronously.

  • Prints sync.

✅ Console: o1, i1, sync

Step 8 — Microtask: resume outer() → console.log('o2')

  • Async outer() continues after the await.

  • Prints o2.

✅ Console: o1, i1, sync, o2

Step 9 — Microtask: p

  • Prints p.

✅ Final Console: o1, i1, sync, o2, p

for (let i = 0; i < 3; i++) {
  Promise.resolve().then(() => console.log('p', i));
}
console.log('loop end');

// loop end
// p 0
// p 1
// p 2

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1loop iteration setup——
2Promise.resolve().then(...) for i=0Microtask queued: p 0—
3Promise.resolve().then(...) for i=1Microtask queued: p 1—
4Promise.resolve().then(...) for i=2Microtask queued: p 2—
5console.log('loop end')Microtasks pending: p0, p1, p2loop end
6(microtask) run p 0Remaining: p1, p2loop end, p 0
7(microtask) run p 1Remaining: p2loop end, p 0, p 1
8(microtask) run p 2—loop end, p 0, p 1, p 2

Step-by-Step Explanation

Step 1 — Loop starts

  • The for loop runs 3 times (i = 0, 1, 2).

Step 2 — For i = 0: Promise.resolve().then(...)

  • Schedules microtask: console.log('p', 0).

Step 3 — For i = 1: Promise.resolve().then(...)

  • Schedules microtask: console.log('p', 1).

Step 4 — For i = 2: Promise.resolve().then(...)

  • Schedules microtask: console.log('p', 2).

Step 5 — console.log('loop end')

  • Runs synchronously.

  • Prints loop end.

✅ Console: loop end

Step 6 — Microtask: run p 0

  • Prints p 0.

✅ Console: loop end, p 0

Step 7 — Microtask: run p 1

  • Prints p 1.

✅ Console: loop end, p 0, p 1

Step 8 — Microtask: run p 2

  • Prints p 2.

✅ Final Console: loop end, p 0, p 1, p 2

for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log('t', i), 0);
}
Promise.resolve().then(() => console.log('p'));
console.log('done');

// done
// p
// t 3
// t 3
// t 3

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1loop iteration (0→1→2→3)Macrotasks queued: t 3, t 3, t 3—
2Promise.resolve().then(...)Microtask queued: p—
3console.log('done')Microtasks pending: pdone
4(microtask) pMacrotasks pending: t 3, t 3, t 3done, p
5(macrotask) t 3Remaining: 2 timeoutsdone, p, t 3
6(macrotask) t 3Remaining: 1 timeoutdone, p, t 3, t 3
7(macrotask) t 3—done, p, t 3, t 3, t 3

Step-by-Step Explanation

Step 1 — for loop with var i

  • var i is function-scoped, so all callbacks share the same i.

  • Loop finishes with i = 3.

  • All three setTimeout callbacks are queued as macrotasks, each printing t 3 when executed.

Step 2 — Promise.resolve().then(...)

  • Schedules a microtask that prints p.

Step 3 — console.log('done')

  • Runs immediately.

  • Prints done.

✅ Console: done

Step 4 — Microtask: run p

  • Prints p.

✅ Console: done, p

Step 5 — Macrotasks: three setTimeout callbacks

All run one by one:

  • First callback prints t 3

  • Second callback prints t 3

  • Third callback prints t 3

✅ Final Console:
done, p, t 3, t 3, t 3

console.log('start');
Promise.resolve().then(() => {
  console.log('p1');
  return Promise.resolve().then(() => console.log('p1.1'));
}).then(() => console.log('p2'));
console.log('end');

// start
// end
// p1
// p1.1
// p2

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1console.log('start')—start
2Promise.resolve().then(...)Microtask queued: p1start
3console.log('end')Microtasks pending: p1start, end
4(microtask) run p1Microtask queued: p1.1start, end, p1
5(microtask) run p1.1Microtask queued: p2start, end, p1, p1.1
6(microtask) run p2—start, end, p1, p1.1, p2

Step-by-Step Explanation

Step 1 — console.log('start')

  • Runs immediately.

  • Prints start.

✅ Console: start

Step 2 — Promise.resolve().then(() => { ... })

  • Schedules a microtask that will print p1.

Step 3 — console.log('end')

  • Runs synchronously.

  • Prints end.

✅ Console: start, end

Step 4 — Microtask: run p1

  • Prints p1.

  • The inner Promise.resolve().then(() => console.log('p1.1')) schedules a new microtask p1.1.

✅ Console: start, end, p1

Step 5 — Microtask: run p1.1

  • Prints p1.1.

  • After the entire first chain finishes, its outer .then(() => console.log('p2')) queues another microtask p2.

✅ Console: start, end, p1, p1.1

Step 6 — Microtask: run p2

  • Prints p2.

✅ Final Console: start, end, p1, p1.1, p2

(async () => {
  console.log('X');
  await Promise.resolve();
  console.log('Y');
})();
queueMicrotask(() => console.log('QM'));
Promise.resolve().then(() => console.log('P'));
console.log('S');

// X
// S
// Y
// QM
// P

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1(async IIFE) start → console.log('X')—X
2await Promise.resolve()Microtask: resume IIFE → YX
3queueMicrotask(...)Microtask queued: QMX
4Promise.resolve().then(...)Microtask queued: PX
5console.log('S')Microtasks pending: Y, QM, PX, S
6(microtask) resume async → YRemaining: QM, PX, S, Y
7(microtask) QMRemaining: PX, S, Y, QM
8(microtask) P—X, S, Y, QM, P

Step-by-Step Explanation

Step 1 — async IIFE begins → console.log('X')

  • The IIFE starts executing immediately.

  • Prints X.

✅ Console: X

Step 2 — await Promise.resolve()

  • Pauses the async function.

  • Schedules a microtask that will later print Y.

Step 3 — queueMicrotask(() => console.log('QM'))

  • Schedules microtask QM.

Step 4 — Promise.resolve().then(() => console.log('P'))

  • Schedules microtask P.

Step 5 — console.log('S')

  • Final synchronous line prints S.

✅ Console: X, S

Step 6 — Microtask: resume async → console.log('Y')

  • Async function continues.

  • Prints Y.

✅ Console: X, S, Y

Step 7 — Microtask: QM

  • Prints QM.

✅ Console: X, S, Y, QM

Step 8 — Microtask: P

  • Prints P.

✅ Final Console: X, S, Y, QM, P

console.log('s');
Promise.resolve().then(() => {
  console.log('p1');
  queueMicrotask(() => console.log('q inside p'));
});
queueMicrotask(() => console.log('q0'));
console.log('e');

// s
// e
// p1
// q0
// q inside p

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1console.log('s')—s
2Promise.resolve().then(...)Microtask queued: p1s
3queueMicrotask(() => console.log('q0'))Microtasks: p1, q0s
4console.log('e')Microtasks pendings, e
5(microtask) run p1Inside: queueMicrotask → adds q inside ps, e, p1
6(microtask) run q0Remaining: q inside ps, e, p1, q0
7(microtask) run q inside p—s, e, p1, q0, q inside p

Step-by-Step Explanation

Step 1 — console.log('s')

  • Runs immediately.

  • Prints s.

✅ Console: s

Step 2 — Promise.resolve().then(...)

  • .then() schedules microtask p1.

Step 3 — queueMicrotask(() => console.log('q0'))

  • Schedules microtask q0.

  • Current microtask order: p1 → q0.

Step 4 — console.log('e')

  • Prints e.

✅ Console: s, e

Step 5 — Microtask: run p1

  • Prints p1.

  • Inside p1, another microtask is queued: q inside p.

Microtask queue now: q0 → q inside p.

✅ Console: s, e, p1

Step 6 — Microtask: run q0

  • Prints q0.

Next microtask: q inside p.

✅ Console: s, e, p1, q0

Step 7 — Microtask: run q inside p

  • Prints q inside p.

This is the final microtask.

✅ Final Console: s, e, p1, q0, q inside p

async function a() {
  console.log('a start');
  await Promise.resolve().then(() => console.log('a inner'));
  console.log('a end');
}
a();
console.log('after');

// a start
// after
// a inner
// a end

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1a()——
2Inside a: console.log('a start')—a start
3Inside a: await Promise.resolve().then(...)Microtask: run a inner → then resume a() with a enda start
4console.log('after')Microtasks pending: a inner, then resume async → a enda start, after
5(microtask) run a innerNext microtask queued: resume async part → a enda start, after, a inner
6(microtask) resume async → console.log('a end')—a start, after, a inner, a end

Step-by-Step Explanation

Step 1 — a()

  • Async function a() is called.

  • Execution enters the function.

Step 2 — Inside a: console.log('a start')

  • Runs immediately.

  • Prints a start.

✅ Console: a start

Step 3 — await Promise.resolve().then(() => console.log('a inner'))

  • The .then() schedules microtask a inner.

  • await pauses a() and schedules another microtask to later continue a() and print a end.

Step 4 — console.log('after')

  • Executes synchronously after calling a().

  • Prints after.

✅ Console: a start, after

Step 5 — Microtask: run a inner

  • Prints a inner.

✅ Console: a start, after, a inner

Step 6 — Microtask: resume async → console.log('a end')

  • Async function continues after the awaited chain.

  • Prints a end.

✅ Final Console: a start, after, a inner, a end

setTimeout(() => console.log('t1'), 0);
Promise.resolve().then(() => {
  console.log('p1');
  setTimeout(() => console.log('t2'), 0);
});
console.log('sync');

// sync
// p1
// t1
// t2

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1setTimeout(t1)Macrotask queued: t1—
2Promise.resolve().then(...)Microtask queued: p1—
3console.log('sync')Microtask pending: p1sync
4(microtask) run p1Macrotask added: t2sync, p1
5(macrotask) run t1Remaining: t2sync, p1, t1
6(macrotask) run t2—sync, p1, t1, t2

Step-by-Step Explanation

Step 1 — setTimeout(() => console.log('t1'), 0)

  • Schedules macrotask t1.

Step 2 — Promise.resolve().then(...)

  • Schedules microtask p1.

Step 3 — console.log('sync')

  • Executes synchronously.

  • Prints sync.

✅ Console: sync

Step 4 — Microtask: run p1

  • Prints p1.

  • Inside it, another setTimeout(() => console.log('t2')) schedules macrotask t2.

✅ Console: sync, p1

Step 5 — Macrotask: run t1

  • Prints t1.

✅ Console: sync, p1, t1

Step 6 — Macrotask: run t2

  • Prints t2.

✅ Final Console: sync, p1, t1, t2

console.log('1');
Promise.resolve().then(() => console.log('2'));
(async () => {
  await 0;
  console.log('3');
})();
console.log('4');

// 1
// 4
// 2
// 3

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1console.log('1')—1
2Promise.resolve().then(...)Microtask queued: 21
3async IIFE call—1
4inside async: await 0Microtask queued: resume async → 31
5console.log('4')Microtasks pending: 2, 31, 4
6(microtask) run 2Remaining: 31, 4, 2
7(microtask) run 3—1, 4, 2, 3

Step-by-Step Explanation

Step 1 — console.log('1')

  • Runs immediately.

  • Prints 1.

✅ Console: 1

Step 2 — Promise.resolve().then(() => console.log('2'))

  • Schedules microtask 2.

Step 3 — Async IIFE executes

  • Enters the async function.

Step 4 — await 0

  • Pauses the async function.

  • Schedules a microtask to later print 3.

Step 5 — console.log('4')

  • Runs synchronously.

  • Prints 4.

✅ Console: 1, 4

Step 6 — Microtask: 2

  • Prints 2.

✅ Console: 1, 4, 2

Step 7 — Microtask: async resumes → 3

  • Async function continues.

  • Prints 3.

✅ Final Console: 1, 4, 2, 3

let x = Promise.resolve(1);
x.then(v => {
  console.log('a', v);
  return 2;
}).then(v => console.log('b', v));
Promise.resolve().then(() => console.log('c'));

// a 1
// c
// b 2

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1Promise.resolve(1) → stored in x——
2x.then(...)Microtask queued: a 1—
3second .then(...) registered(runs after a 1)—
4Promise.resolve().then(...)Microtask queued: c—
5(end of sync)Microtasks pending: a1, b2, c—
6(microtask) run first then → a 1Microtask queued: b 2a 1
7(microtask) run second then → b 2Remaining: ca 1, b 2
8(microtask) run c—a 1, b 2, c

Step-by-Step Explanation

Step 1 — let x = Promise.resolve(1)

  • Creates an already-resolved promise with value 1.

  • No console output.

Step 2 — x.then(v => {...})

  • Schedules a microtask that will later print a 1.

Step 3 — .then(v => console.log('b', v))

  • This second .then is chained.

  • It will run only after the first .then resolves and returns 2.

Step 4 — Promise.resolve().then(() => console.log('c'))

  • Adds another microtask: c.

Step 5 — End of synchronous code

  • Nothing printed yet.

  • Pending microtasks (in order):

    1. a 1

    2. b 2

    3. c

Step 6 — Microtask: first .then → prints a 1

  • Runs with value 1.

  • Prints a 1.

  • Returns 2, which queues next microtask: b 2.

✅ Console: a 1

Step 7 — Microtask: second .then → prints b 2

  • Runs with value 2.

✅ Console: a 1, b 2

Step 8 — Microtask: c

  • Prints c.

✅ Final Console: a 1, b 2, c

console.log('s');
Promise.resolve().then(() => {
  console.log('p1');
  return Promise.resolve().then(() => console.log('p1.1'));
}).then(() => console.log('p2'));
console.log('e');

// s
// e
// p1
// p1.1
// p2

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1console.log('s')—s
2Promise.resolve().then(...)Microtask queued: p1s
3console.log('e')Microtasks pending: p1s, e
4(microtask) run p1Microtask queued: p1.1s, e, p1
5(microtask) run p1.1Task chained → microtask queued: p2s, e, p1, p1.1
6(microtask) run p2—s, e, p1, p1.1, p2

Step-by-Step Explanation

Step 1 — console.log('s')

  • Executes immediately.

  • Prints s.

✅ Console: s

Step 2 — Promise.resolve().then(...)

  • Registers a microtask that will run p1.

Step 3 — console.log('e')

  • Executes synchronously.

  • Prints e.

✅ Console: s, e

Step 4 — Microtask: run p1

  • Prints p1.

  • The inner return Promise.resolve().then(...) queues microtask p1.1.

✅ Console: s, e, p1

Step 5 — Microtask: run p1.1

  • Prints p1.1.

  • After this finishes, the chained .then(() => console.log('p2')) schedules microtask p2.

✅ Console: s, e, p1, p1.1

Step 6 — Microtask: run p2

  • Prints p2.

✅ Final Console: s, e, p1, p1.1, p2

async function f() {
  console.log('f1');
  await Promise.resolve();
  console.log('f2');
}
Promise.resolve().then(() => console.log('p'));
f();
console.log('sync');

// f1
// sync
// p
// f2

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1Promise.resolve().then(...)Microtask queued: p—
2f()——
3Inside f: console.log('f1')—f1
4Inside f: await Promise.resolve()Microtask queued: resume f() → f2f1
5console.log('sync')Microtasks pending: p, f2f1, sync
6(microtask) pRemaining: f2f1, sync, p
7(microtask) resume async → f2—f1, sync, p, f2

Step-by-Step Explanation

Step 1 — Promise.resolve().then(() => console.log('p'))

  • Schedules a microtask that will print p later.

Step 2 — f()

  • Async function f() is called.

  • Execution enters the function.

Step 3 — Inside f: console.log('f1')

  • Synchronous.

  • Prints f1.

✅ Console: f1

Step 4 — Inside f: await Promise.resolve()

  • await pauses f().

  • Schedules a microtask that will later print f2.

Step 5 — console.log('sync')

  • Executes synchronously.

  • Prints sync.

✅ Console: f1, sync

Step 6 — Microtask: run p

  • Prints p.

✅ Console: f1, sync, p

Step 7 — Microtask: resume async → console.log('f2')

  • f() continues after the await.

  • Prints f2.

✅ Final Console: f1, sync, p, f2

console.log('start');
Promise.resolve().then(() => console.log('p1'));
queueMicrotask(() => console.log('qm1'));
Promise.resolve().then(() => console.log('p2'));
console.log('end');

// start
// end
// p1
// qm1
// p2

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1console.log('start')—start
2Promise.resolve().then(p1)Microtask queued: p1start
3queueMicrotask(qm1)Microtask queued: qm1start
4Promise.resolve().then(p2)Microtask queued: p2start
5console.log('end')Microtasks pending: p1, qm1, p2start, end
6(microtask) run p1Remaining: qm1, p2start, end, p1
7(microtask) run qm1Remaining: p2start, end, p1, qm1
8(microtask) run p2—start, end, p1, qm1, p2

Step-by-Step Explanation

Step 1 — console.log('start')

  • Executes immediately.

  • Prints start.

✅ Console: start

Step 2 — .then(() => console.log('p1'))

  • Schedules microtask p1.

Step 3 — queueMicrotask(() => console.log('qm1'))

  • Schedules microtask qm1.

Step 4 — .then(() => console.log('p2'))

  • Schedules microtask p2.

Step 5 — console.log('end')

  • Executes synchronously.

  • Prints end.

✅ Console: start, end

Step 6 — Microtask: p1

  • Runs first in the microtask queue.

  • Prints p1.

✅ Console: start, end, p1

Step 7 — Microtask: qm1

  • Executes next.

  • Prints qm1.

✅ Console: start, end, p1, qm1

Step 8 — Microtask: p2

  • Final microtask.

  • Prints p2.

✅ Final Console: start, end, p1, qm1, p2

(async () => {
  console.log('a');
  await new Promise(res => {
    console.log('executor');
    res();
  });
  console.log('b');
})();
console.log('c');

// a
// executor
// c
// b

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1(async IIFE) call——
2Inside IIFE: console.log('a')—a
3new Promise(res => { console.log('executor'); res(); })Microtask queued: resume → print ba, executor
4console.log('c')Microtasks pending: resume asynca, executor, c
5(microtask) resume async → console.log('b')—a, executor, c, b

Step-by-Step Explanation

Step 1 — Async IIFE runs

  • The async IIFE is invoked immediately.

  • Execution enters the function body.

Step 2 — console.log('a')

  • Runs synchronously.

  • Prints a.

✅ Console: a

Step 3 — await new Promise(...)

  • The Promise executor runs immediately.

  • Inside the executor:

    • console.log('executor') prints executor

    • res() resolves the Promise instantly

  • Because of await, the async function pauses.

  • The continuation (printing b) is placed in the Microtask Queue.

✅ Console: a, executor

Step 4 — console.log('c')

  • Runs after the async function yields.

  • Prints c.

✅ Console: a, executor, c

Step 5 — Microtask: resume async → console.log('b')

  • Async function resumes after the awaited Promise.

  • Prints b.

✅ Final Console: a, executor, c, b

console.log('s');
Promise.resolve().then(() => {
  console.log('p1');
  queueMicrotask(() => console.log('q1'));
});
queueMicrotask(() => console.log('q0'));
console.log('e');

// s
// e
// p1
// q0
// q1

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1console.log('s')—s
2Promise.resolve().then(...)Microtask queued: p1s
3queueMicrotask(q0)Microtask queued: q0s
4console.log('e')Microtasks pending: p1, q0s, e
5(microtask) run p1queues q1s, e, p1
6(microtask) run q0Microtasks: q1s, e, p1, q0
7(microtask) run q1—s, e, p1, q0, q1

Step-by-Step Explanation

Step 1 — console.log('s')

  • Executes immediately.

  • Prints s.

✅ Console: s

Step 2 — Promise.resolve().then(...)

  • Schedules microtask p1.

Step 3 — queueMicrotask(() => console.log('q0'))

  • Schedules microtask q0.

Step 4 — console.log('e')

  • Executes synchronously.

  • Prints e.

✅ Console: s, e

Step 5 — Microtask: run p1

  • Prints p1.

  • Inside it, queueMicrotask(q1) schedules q1.

✅ Console: s, e, p1

Step 6 — Microtask: run q0

  • Runs next (queued earlier than q1).

  • Prints q0.

✅ Console: s, e, p1, q0

Step 7 — Microtask: run q1

  • Runs last.

  • Prints q1.

✅ Final Console: s, e, p1, q0, q1

(async function main() {
  console.log('m1');
  await Promise.resolve();
  console.log('m2');
  await Promise.resolve();
  console.log('m3');
})();
console.log('after main');

// m1
// after main
// m2
// m3

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1main()——
2Inside main: console.log('m1')—m1
3Inside main: await Promise.resolve()Microtask queued: resume → run m2m1
4console.log('after main')Microtask pending: m2m1, after main
5(microtask) resume main → console.log('m2')Microtask queued: resume → run m3m1, after main, m2
6(microtask) resume main after second await → console.log('m3')—m1, after main, m2, m3

Step-by-Step Explanation

Step 1 — main()

  • The async IIFE main() begins running immediately.

  • Execution moves inside the function.

Step 2 — console.log('m1')

  • Runs synchronously.

  • Prints m1.

✅ Console: m1

Step 3 — First await Promise.resolve()

  • await pauses main().

  • A microtask is scheduled to continue with console.log('m2').

Step 4 — console.log('after main')

  • Runs while main() is paused.

  • Prints after main.

✅ Console: m1, after main

Step 5 — Microtask: resume → console.log('m2')

  • Async function continues after first await.

  • Prints m2.

  • The second await Promise.resolve() pauses again and schedules another microtask.

✅ Console: m1, after main, m2

Step 6 — Microtask: resume → console.log('m3')

  • Async function resumes after second await.

  • Prints m3.

✅ Final Console: m1, after main, m2, m3

console.log('start');
Promise.resolve().then(() => {
  console.log('p1');
  return Promise.resolve('v');
}).then(v => console.log('then', v));
console.log('end');

// start
// end
// p1
// then v

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1console.log('start')—start
2Promise.resolve().then(...)Microtask queued: p1start
3.then(v => console.log('then', v)) is registeredWill queue after p1start
4console.log('end')Microtasks: p1 then then vstart, end
5(microtask) run p1Schedules next microtask: then('v')start, end, p1
6(microtask) run then('v')—start, end, p1, then v

Step-by-Step Explanation

Step 1 — console.log('start')

  • Runs immediately.

  • Prints start.

✅ Console: start

Step 2 — Promise.resolve().then(() => {...})

  • .then() schedules a microtask.

  • Microtask p1 is queued.

Step 3 — Second .then(v => console.log('then', v))

  • Registered in the promise chain.

  • Will run after p1 resolves and returns "v".

Step 4 — console.log('end')

  • Last synchronous line.

  • Prints end.

✅ Console: start, end

Step 5 — Microtask: run p1

  • Prints p1.

  • Returns Promise.resolve('v'), which schedules microtask then v.

✅ Console: start, end, p1

Step 6 — Microtask: run then v

  • Prints then v.

✅ Final Console: start, end, p1, then v

for (let i = 0; i < 2; i++) {
  (async () => {
    console.log('ai', i);
    await null;
    console.log('ai after', i);
  })();
}
console.log('loop done');

// ai 0
// ai 1
// loop done
// ai after 0
// ai after 1

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1for loop (i=0) → async IIFE call——
2IIFE(0): console.log('ai', 0)—ai 0
3IIFE(0): await nullMicrotask queued: resume IIFE(0) → ai after 0ai 0
4for loop (i=1) → async IIFE call—ai 0
5IIFE(1): console.log('ai', 1)—ai 0, ai 1
6IIFE(1): await nullMicrotask queued: resume IIFE(1) → ai after 1ai 0, ai 1
7console.log('loop done')Microtasks pending: ai after 0, ai after 1ai 0, ai 1, loop done
8(microtask) resume IIFE(0) → console.log('ai after', 0)Remaining: IIFE(1)ai 0, ai 1, loop done, ai after 0
9(microtask) resume IIFE(1) → console.log('ai after', 1)—ai 0, ai 1, loop done, ai after 0, ai after 1

Step-by-Step Explanation

Step 1 — Loop iteration i = 0

  • Async IIFE is invoked immediately.

  • Control enters IIFE.

Step 2 — Inside IIFE(0): console.log('ai', 0)

  • Runs synchronously.

  • Prints ai 0.

✅ Console: ai 0

Step 3 — await null (IIFE 0)

  • await null yields immediately.

  • Schedules microtask to resume IIFE(0) which will print ai after 0 later.

Step 4 — Loop iteration i = 1

  • Async IIFE is invoked again (new instance).

  • Control enters IIFE.

Step 5 — Inside IIFE(1): console.log('ai', 1)

  • Runs synchronously.

  • Prints ai 1.

✅ Console: ai 0, ai 1

Step 6 — await null (IIFE 1)

  • Schedules microtask to later print ai after 1.

Step 7 — console.log('loop done')

  • Last synchronous line executes.

  • Prints loop done.

✅ Console: ai 0, ai 1, loop done

Step 8 — Microtask: resume IIFE(0) → console.log('ai after', 0)

  • First microtask runs.

  • Prints ai after 0.

✅ Console: ai 0, ai 1, loop done, ai after 0

Step 9 — Microtask: resume IIFE(1) → console.log('ai after', 1)

  • Second microtask runs.

  • Prints ai after 1.

✅ Final Console: ai 0, ai 1, loop done, ai after 0, ai after 1

let p = Promise.resolve();
p.then(() => console.log('1')).then(() => console.log('2'));
queueMicrotask(() => console.log('qm'));
console.log('sync');

// sync
// 1
// qm
// 2

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1console.log('sync')—sync
2p.then(() => console.log('1'))Microtask queued: 1sync
3queueMicrotask(() => console.log('qm'))Microtask queued: qmsync
4(microtask) run 1Microtask queued: 2sync, 1
5(microtask) run qmRemaining: 2sync, 1, qm
6(microtask) run 2—sync, 1, qm, 2

Step-by-Step Explanation

Step 1 — console.log('sync')

  • Runs synchronously.

  • Prints sync.

✅ Console: sync

Step 2 — p.then(() => console.log('1'))

  • Schedules a microtask that will later print 1.

Step 3 — queueMicrotask(() => console.log('qm'))

  • Schedules microtask qm.

  • Microtasks now (in order):

    1. 1

    2. qm

Step 4 — Microtask: run 1

  • Prints 1.

  • Its chained .then(() => console.log('2')) schedules microtask 2.

Microtasks now:

  1. qm

  2. 2

✅ Console: sync, 1

Step 5 — Microtask: run qm

  • Prints qm.

Microtasks now:

  1. 2

✅ Console: sync, 1, qm

Step 6 — Microtask: run 2

  • Prints 2.

✅ Final Console: sync, 1, qm, 2

async function a() {
  console.log('A');
  await Promise.resolve();
  console.log('B');
}
async function b() {
  console.log('C');
  await Promise.resolve();
  console.log('D');
}
a(); b();
console.log('E');

// A
// C
// E
// B
// D

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1a()——
2Inside a: console.log('A')—A
3Inside a: await Promise.resolve()Microtask: resume a() → BA
4b()—A
5Inside b: console.log('C')—A, C
6Inside b: await Promise.resolve()Microtask: resume b() → DA, C
7console.log('E')Microtasks pending: B, DA, C, E
8(microtask) resume a() → BRemaining: DA, C, E, B
9(microtask) resume b() → D—A, C, E, B, D

Step-by-Step Explanation

Step 1 — a()

  • Async function a is called.

  • Execution enters the function.

Step 2 — Inside a: console.log('A')

  • Runs immediately.

  • Prints A.

✅ Console: A

Step 3 — await Promise.resolve() inside a

  • Pauses a.

  • Schedules a microtask to later continue with B.

Step 4 — b()

  • Async function b is called.

  • Execution enters the function.

Step 5 — Inside b: console.log('C')

  • Runs immediately.

  • Prints C.

✅ Console: A, C

Step 6 — await Promise.resolve() inside b

  • Pauses b.

  • Schedules a microtask to later continue with D.

Step 7 — console.log('E')

  • Synchronous.

  • Prints E.

✅ Console: A, C, E

Step 8 — Microtask: resume a() → print B

  • Async a continues.

  • Prints B.

✅ Console: A, C, E, B

Step 9 — Microtask: resume b() → print D

  • Async b continues.

  • Prints D.

✅ Final Console: A, C, E, B, D

console.log('start');
Promise.resolve().then(() => {
  console.log('p1');
  queueMicrotask(() => {
    console.log('q1');
    Promise.resolve().then(() => console.log('p-in-q'));
  });
});
console.log('end');

// start
// end
// p1
// q1
// p-in-q

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1console.log('start')—start
2Promise.resolve().then(...)Microtask queued: p1start
3console.log('end')Microtasks pending: p1start, end
4(microtask) run p1queueMicrotask: q1start, end, p1
5(microtask) run q1Microtask queued: p-in-qstart, end, p1, q1
6(microtask) run p-in-q—start, end, p1, q1, p-in-q

Step-by-Step Explanation

Step 1 — console.log('start')

  • Runs immediately.

  • Prints start.

✅ Console: start

Step 2 — Promise.resolve().then(...)

  • .then() schedules a microtask that will later print p1.

Step 3 — console.log('end')

  • Runs synchronously.

  • Prints end.

✅ Console: start, end

Step 4 — Microtask: run p1

  • Prints p1.

  • Inside p1, queueMicrotask schedules q1.

✅ Console: start, end, p1

Step 5 — Microtask: run q1

  • Prints q1.

  • Inside q1, a new Promise.resolve().then(...) schedules p-in-q.

✅ Console: start, end, p1, q1

Step 6 — Microtask: run p-in-q

  • Prints p-in-q.

✅ Final Console: start, end, p1, q1, p-in-q

(async () => {
  console.log('s');
  await Promise.resolve();
  console.log('p');
  await null;
  console.log('q');
})();
Promise.resolve().then(() => console.log('then1'));
console.log('after');

// s
// after
// p
// then1
// q

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1IIFE call——
2console.log('s')—s
3await Promise.resolve()Microtask queued: resume → ps
4Promise.resolve().then(...)Microtask queued: then1s
5console.log('after')Microtasks pending: p, then1s, after
6(microtask) resume IIFE → console.log('p')Microtask queued: resume for qs, after, p
7(microtask) then1Remaining microtask: resume → qs, after, p, then1
8(microtask) resume IIFE → console.log('q')—s, after, p, then1, q

Step-by-Step Explanation

Step 1 — IIFE begins

  • Async IIFE is invoked.

  • Execution enters the function.

Step 2 — console.log('s')

  • Runs immediately.

  • Prints s.

✅ Console: s

Step 3 — await Promise.resolve()

  • Promise.resolve() resolves instantly.

  • await pauses the async function.

  • Queues a microtask to resume later (to run console.log('p')).

Step 4 — Promise.resolve().then(() => console.log('then1'))

  • Schedules microtask then1.

Step 5 — console.log('after')

  • Runs synchronously.

  • Prints after.

✅ Console: s, after

Step 6 — Microtask: resume async → console.log('p')

  • Async function continues after the first await.

  • Prints p.

  • Next await null schedules another microtask for later (q).

✅ Console: s, after, p

Step 7 — Microtask: then1

  • Prints then1.

✅ Console: s, after, p, then1

Step 8 — Microtask: resume async → console.log('q')

  • Async function resumes after await null.

  • Prints q.

✅ Final Console: s, after, p, then1, q

console.log('start');
Promise.resolve().then(() => console.log('p1'));
setTimeout(() => console.log('t1'), 0);
new Promise(res => res()).then(() => console.log('p2'));
console.log('end');

// start
// end
// p1
// p2
// t1

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1console.log('start')—start
2Promise.resolve().then(...)Microtask queued: p1start
3setTimeout(..., 0)Macrotask queued: t1start
4new Promise(res=>res()).then(...)Microtask queued: p2start
5console.log('end')Microtasks pending: p1, p2start, end
6(microtask) run p1Remaining microtasks: p2start, end, p1
7(microtask) run p2—start, end, p1, p2
8(macrotask) run t1—start, end, p1, p2, t1

Step-by-Step Explanation

Step 1 — console.log('start')

  • Runs immediately.

  • Prints start.

✅ Console: start

Step 2 — Promise.resolve().then(() => console.log('p1'))

  • Schedules microtask p1.

Step 3 — setTimeout(() => console.log('t1'), 0)

  • Schedules macrotask t1.

Step 4 — new Promise(res=>res()).then(() => console.log('p2'))

  • The executor resolves instantly.

  • Schedules microtask p2.

Step 5 — console.log('end')

  • Prints end.

✅ Console: start, end

Step 6 — Microtask: p1

  • Prints p1.

✅ Console: start, end, p1

Step 7 — Microtask: p2

  • Prints p2.

✅ Console: start, end, p1, p2

Step 8 — Macrotask: t1

  • Event loop moves to macrotasks.

  • Prints t1.

✅ Final Console: start, end, p1, p2, t1

(async () => {
  await Promise.resolve();
  console.log('a');
})();
Promise.resolve().then(() => console.log('b'));
queueMicrotask(() => console.log('c'));
console.log('d');

// d
// a
// b
// c

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1(async IIFE call)——
2Inside IIFE: await Promise.resolve()Microtask queued: resume → a—
3Promise.resolve().then(...)Microtask queued: b—
4queueMicrotask(...)Microtask queued: c—
5console.log('d')Microtasks pending: a, b, cd
6(microtask) resume async → aRemaining: b, cd, a
7(microtask) bRemaining: cd, a, b
8(microtask) c—d, a, b, c

Step-by-Step Explanation

Step 1 — Async IIFE runs

  • The async function starts execution.

  • Hits the first line: await Promise.resolve().

Step 2 — await Promise.resolve()

  • The promise resolves immediately.

  • The continuation (logging a) is placed into the Microtask Queue.

  • Execution of the async function pauses.

Step 3 — Promise.resolve().then(() => console.log('b'))

  • Schedules a microtask that will print b.

Step 4 — queueMicrotask(() => console.log('c'))

  • Schedules microtask c.

Step 5 — console.log('d')

  • Runs synchronously.

  • Prints d.

✅ Console: d

Step 6 — Microtask: resume async → console.log('a')

  • Execution continues after the await.

  • Prints a.

✅ Console: d, a

Step 7 — Microtask: b

  • Runs next.

  • Prints b.

✅ Console: d, a, b

Step 8 — Microtask: c

  • Final microtask prints c.

✅ Final Console: d, a, b, c

console.log('s');
Promise.resolve().then(() => {
  console.log('p1');
  return Promise.resolve().then(() => console.log('p1.1'));
}).then(() => console.log('p2'));
queueMicrotask(() => console.log('qm'));
console.log('e');

// s
// e
// p1
// qm
// p1.1
// p2

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1console.log('s')—s
2Promise.resolve().then(...)Microtask: p1s
3queueMicrotask(...)Microtask: qm (after p1)s
4console.log('e')Microtasks pending: p1, qms, e
5(microtask) run p1New microtask added: p1.1s, e, p1
6(microtask) run p1.1Next: p2, qms, e, p1, p1.1
7(microtask) run p2Next: qms, e, p1, p1.1, p2
8(microtask) run qm—s, e, p1, p1.1, p2, qm

Step-by-Step Explanation

Step 1 — console.log('s')

  • Runs immediately.

  • Prints s.

✅ Console: s

Step 2 — First .then() schedules microtask p1

  • Promise.resolve().then(...) registers a microtask.

  • p1 is added to the Microtask Queue.

Step 3 — queueMicrotask(() => console.log('qm'))

  • Schedules another microtask qm, placed after p1.

Step 4 — console.log('e')

  • Prints e.

✅ Console: s, e

Step 5 — Microtask: p1

  • Runs p1.

  • Prints p1.

  • Inside it, a new promise resolves and schedules microtask p1.1.

✅ Console: s, e, p1

Step 6 — Microtask: p1.1

  • Runs next.

  • Prints p1.1.

✅ Console: s, e, p1, p1.1

Step 7 — Microtask: p2

  • The parent .then() resolves after p1.

  • Prints p2.

✅ Console: s, e, p1, p1.1, p2

Step 8 — Microtask: qm

  • Finally the queued microtask qm runs.

  • Prints qm.

✅ Final Console: s, e, p1, p1.1, p2, qm

(async function test() {
  console.log('x');
  await 0;
  console.log('y');
})();
setTimeout(() => console.log('t'), 0);
Promise.resolve().then(() => console.log('p'));
console.log('z');

// x
// z
// y
// p
// t

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1console.log('x')—x
2await 0 suspends asyncMicrotask: resume → yx
3setTimeout(...,0)Macrotask queued: tx
4Promise.resolve().then(...)Microtask queued: px
5console.log('z')Microtasks pending: y, px, z
6(microtask) resume async → yRemaining: px, z, y
7(microtask) run p—x, z, y, p
8(macrotask) run t—x, z, y, p, t

Step-by-Step Explanation

Step 1 — console.log('x')

  • Runs immediately inside the async IIFE.

  • Prints x.

✅ Console: x

Step 2 — await 0

  • await 0 is equivalent to await Promise.resolve(0).

  • The async function pauses.

  • A microtask is queued to resume later and run console.log('y').

Step 3 — setTimeout(() => console.log('t'), 0)

  • Schedules a macrotask: t.

Step 4 — Promise.resolve().then(() => console.log('p'))

  • Schedules microtask p.

Step 5 — console.log('z')

  • Runs synchronously.

  • Prints z.

✅ Console: x, z

Step 6 — Microtask: resume async → console.log('y')

  • Async function continues after await.

  • Prints y.

✅ Console: x, z, y

Step 7 — Microtask: p

  • Prints p.

✅ Console: x, z, y, p

Step 8 — Macrotask: t

  • Event loop moves to macrotasks.

  • Prints t.

✅ Final Console: x, z, y, p, t

console.log('start');
Promise.resolve().then(() => {
  console.log('p1');
  queueMicrotask(() => console.log('q1'));
}).then(() => console.log('p2'));
queueMicrotask(() => console.log('q0'));
console.log('end');

// start
// end
// p1
// q0
// q1
// p2

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1console.log('start')—start
2Promise.resolve().then(...)Microtask queued: p1start
3queueMicrotask(q0)Microtask queued: q0start
4console.log('end')Microtasks pending: p1, q0start, end
5(microtask) run p1queues: q1, and schedules next .then → microtask p2start, end, p1
6(microtask) run p2pending: q0, q1start, end, p1, p2
7(microtask) run q0pending: q1start, end, p1, p2, q0
8(microtask) run q1—start, end, p1, p2, q0, q1

Step-by-Step Explanation

Step 1 — console.log('start')

  • Executes immediately.

  • Prints start.

✅ Console: start

Step 2 — Promise.resolve().then(...)

  • Schedules the microtask p1.

Step 3 — queueMicrotask(() => console.log('q0'))

  • Schedules q0.

Step 4 — console.log('end')

  • Runs synchronously.

  • Prints end.

✅ Console: start, end

Step 5 — Microtask: run p1

  • Prints p1.

  • Inside p1:

    • Schedules q1.

    • The chained .then(() => console.log('p2')) schedules microtask p2.

✅ Console: start, end, p1

Step 6 — Microtask: p2

  • Prints p2.

✅ Console: start, end, p1, p2

Step 7 — Microtask: q0

  • Prints q0.

✅ Console: start, end, p1, p2, q0

Step 8 — Microtask: q1

  • Prints q1.

✅ Final Console: start, end, p1, p2, q0, q1

(async () => {
  console.log('A');
  await Promise.resolve();
  console.log('B');
  Promise.resolve().then(() => console.log('C'));
})();
console.log('D');

// A
// D
// B
// C

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1IIFE call——
2console.log('A')—A
3await Promise.resolve()Microtask: resume → print BA
4console.log('D')Microtasks pending: BA, D
5(microtask) resume async → console.log('B')Microtask queued: CA, D, B
6(microtask) run C—A, D, B, C

Step-by-Step Explanation

Step 1 — Start async IIFE

  • The async function executes immediately.

Step 2 — console.log('A')

  • Runs synchronously.

  • Prints A.

✅ Console: A

Step 3 — await Promise.resolve()

  • await pauses the function.

  • Schedules a microtask that will later print B.

Step 4 — console.log('D')

  • Next synchronous statement.

  • Prints D.

✅ Console: A, D

Step 5 — Microtask: resume async → console.log('B')

  • Async function continues after the await.

  • Prints B.

  • Inside it, Promise.resolve().then(() => console.log('C')) schedules microtask C.

✅ Console: A, D, B

Step 6 — Microtask: run C

  • Prints C.

✅ Final Console: A, D, B, C

console.log('s');
Promise.resolve().then(() => {
  console.log('p1');
  Promise.resolve().then(() => console.log('p1.1'));
});
queueMicrotask(() => console.log('qm'));
console.log('e');

// s
// e
// p1
// qm
// p1.1

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1console.log('s')—s
2Promise.resolve().then(...)Microtask queued: p1s
3queueMicrotask(...)Microtask queued: qms
4console.log('e')Microtasks pending: p1, qms, e
5(microtask) run p1New microtask queued: p1.1s, e, p1
6(microtask) run p1.1Remaining: qms, e, p1, p1.1
7(microtask) run qm—s, e, p1, p1.1, qm

Step-by-Step Explanation

Step 1 — console.log('s')

  • Runs immediately.

  • Prints s.

✅ Console: s

Step 2 — Promise.resolve().then(...)

  • .then() schedules microtask p1.

Step 3 — queueMicrotask(() => console.log('qm'))

  • Microtask qm is added after p1.

Step 4 — console.log('e')

  • Synchronous log prints e.

✅ Console: s, e

Step 5 — Microtask: run p1

  • Prints p1.

  • Inside p1, another Promise.resolve().then schedules p1.1.

✅ Console: s, e, p1

Step 6 — Microtask: run p1.1

  • Prints p1.1.

✅ Console: s, e, p1, p1.1

Step 7 — Microtask: run qm

  • Prints qm.

✅ Final Console: s, e, p1, p1.1, qm

(async function run() {
  console.log('start');
  await Promise.resolve();
  console.log('mid');
  await Promise.resolve();
  console.log('end');
})();
console.log('after');

// start
// after
// mid
// end

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1(async run())——
2Inside run: console.log('start')—start
3Inside run: await Promise.resolve()Microtask queued: resume → print midstart
4console.log('after')Microtasks pending: midstart, after
5(microtask) resume async → console.log('mid')Microtask queued: resume → print endstart, after, mid
6(microtask) resume async → console.log('end')—start, after, mid, end

Step-by-Step Explanation

Step 1 — Call run() (async IIFE)

  • The async function starts executing immediately.

Step 2 — Inside run: console.log('start')

  • Prints start.

✅ Console: start

Step 3 — await Promise.resolve()

  • Pauses run() execution.

  • Schedules a microtask to resume later and print mid.

Step 4 — console.log('after')

  • Synchronous code outside the async runs.

  • Prints after.

✅ Console: start, after

Step 5 — Microtask: resume async → console.log('mid')

  • First microtask resumes the async function.

  • Prints mid.

  • The next await Promise.resolve() schedules another microtask to print end.

✅ Console: start, after, mid

Step 6 — Microtask: resume async → console.log('end')

  • Final microtask prints end.

✅ Final Console: start, after, mid, end

console.log('1');
Promise.resolve().then(() => {
  console.log('2');
  queueMicrotask(() => console.log('2.qm'));
});
queueMicrotask(() => console.log('qm1'));
Promise.resolve().then(() => console.log('3'));
console.log('4');

// 1
// 4
// 2
// qm1
// 3
// 2.qm

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1console.log('1')—1
2Promise.resolve().then(...)Microtask: 21
3queueMicrotask(...)Microtask: 2, qm11
4Promise.resolve().then(...)Microtask: 2, qm1, 31
5console.log('4')Microtasks pending: 2, qm1, 31, 4
6(microtask) run 2queueMicrotask: 2.qm; remaining: qm1, 3, 2.qm1, 4, 2
7(microtask) run qm1remaining: 3, 2.qm1, 4, 2, qm1
8(microtask) run 3remaining: 2.qm1, 4, 2, qm1, 3
9(microtask) run 2.qm—1, 4, 2, qm1, 3, 2.qm

Step-by-Step Explanation

Step 1 — console.log('1')

  • Runs immediately.

  • Prints 1.

✅ Console: 1

Step 2 — First Promise.resolve().then(...)

  • Schedules microtask 2.

Step 3 — queueMicrotask(() => console.log('qm1'))

  • Schedules microtask qm1 after 2.

Step 4 — Second Promise.resolve().then(...)

  • Schedules microtask 3 after 2, qm1.

Step 5 — console.log('4')

  • Prints 4.

✅ Console: 1, 4

Step 6 — Microtask: run 2

  • Prints 2.

  • Inside it: schedules microtask 2.qm.

  • Queue becomes: qm1, 3, 2.qm.

✅ Console: 1, 4, 2

Step 7 — Microtask: run qm1

  • Prints qm1.

✅ Console: 1, 4, 2, qm1

Step 8 — Microtask: run 3

  • Prints 3.

✅ Console: 1, 4, 2, qm1, 3

Step 9 — Microtask: run 2.qm

  • Prints 2.qm.

✅ Final Console:
1, 4, 2, qm1, 3, 2.qm

(async () => {
  console.log('t1');
  await Promise.resolve().then(() => console.log('inner'));
  console.log('t2');
})();
Promise.resolve().then(() => console.log('p'));
console.log('sync');

// t1
// sync
// inner
// p
// t2

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1IIFE call——
2console.log('t1')—t1
3await Promise.resolve().then(...)Microtask: innert1
4Promise.resolve().then(() => console.log('p'))Microtask queued: pt1
5console.log('sync')Microtasks: inner, then p, then resume → t2t1, sync
6(microtask) innerMicrotasks left: p, resume asynct1, sync, inner
7(microtask) pMicrotasks left: resume asynct1, sync, inner, p
8(microtask) resume async → console.log('t2')—t1, sync, inner, p, t2

Step-by-Step Explanation

Step 1 — IIFE runs

  • The async IIFE begins executing immediately.

Step 2 — console.log('t1')

  • Runs synchronously.

  • Prints t1.

✅ Console: t1

Step 3 — await Promise.resolve().then(() => console.log('inner'))

  • The .then() schedules the microtask inner.

  • await pauses the async function.

  • Remaining part (t2) goes to the microtask queue (after inner).

Step 4 — Promise.resolve().then(() => console.log('p'))

  • Schedules microtask p.

Step 5 — console.log('sync')

  • Runs synchronously.

  • Prints sync.

✅ Console: t1, sync

Step 6 — Microtask: inner

  • Prints inner.

✅ Console: t1, sync, inner

Step 7 — Microtask: p

  • Prints p.

✅ Console: t1, sync, inner, p

Step 8 — Resume async function → console.log('t2')

  • The async function continues after the final await.

  • Prints t2.

✅ Final Console: t1, sync, inner, p, t2

console.log('start');
Promise.resolve().then(() => {
  console.log('p1');
  return new Promise(res => res('v'));
}).then(v => console.log('then', v));
console.log('end');

// start
// end
// p1
// then v

Execution Table

StepCall StackWeb APIs / QueuesConsole Output
1console.log('start')—start
2Promise.resolve().then(...)Microtask queued: p1start
3console.log('end')Microtasks pending: p1start, end
4(microtask) run p1New Promise created → resolves → microtask queued to continue chain with value "v"start, end, p1
5(microtask) run chained .then(v => console.log('then', v))—start, end, p1, then v

Step-by-Step Explanation

Step 1 — console.log('start')

  • Runs synchronously.

  • Prints start.

✅ Console: start

Step 2 — Promise.resolve().then(...)

  • Schedules microtask p1.

Step 3 — console.log('end')

  • Runs synchronously.

  • Prints end.

✅ Console: start, end

Step 4 — Microtask: run p1

  • Prints p1.

  • Returns a new Promise whose executor resolves immediately (res('v')).

  • Because it resolves instantly, the chained .then(...) is added as a new microtask.

✅ Console: start, end, p1

Step 5 — Microtask: chained .then(v => console.log('then', v))

  • Receives "v" and prints:

then v

✅ Final Console: start, end, p1, then v

Too long for revision? Here is a pattern structure to start thinking about any questions.

PATTERN 1 — Basic Execution + setTimeout + Promise

console.log("A");
setTimeout(() => console.log("T1"));
Promise.resolve().then(() => console.log("P1"));
console.log("B");

PATTERN 2 — Promise Chain Ordering

console.log("A");
Promise.resolve()
  .then(() => console.log("P1"))
  .then(() => console.log("P2"));
console.log("B");

PATTERN 3 — Promise Inside setTimeout

setTimeout(() => {
  console.log("T1");
  Promise.resolve().then(() => console.log("P1"));
});
console.log("A");

PATTERN 4 — Async/Await With Microtasks

async function f() {
  console.log("F1");
  await null;
  console.log("F2");
}
console.log("A");
f();
console.log("B");

PATTERN 5 — Async + Promise Mix

async function f() {
  console.log("F1");
  await Promise.resolve().then(() => console.log("P1"));
  console.log("F2");
}
console.log("A");
f();
console.log("B");

PATTERN 6 — Multiple Awaits & Interleaving

async function f() {
  console.log("F1");
  await 0;
  console.log("F2");
  await 0;
  console.log("F3");
}
console.log("A");
f();
console.log("B");

PATTERN 7 — Nested Promises

console.log("A");
Promise.resolve().then(() => {
  console.log("P1");
  Promise.resolve().then(() => console.log("P2"));
});
console.log("B");

PATTERN 8 — Nested setTimeout + Promise

setTimeout(() => {
  console.log("T1");
  Promise.resolve().then(() => console.log("P1"));
  setTimeout(() => console.log("T2"));
});
console.log("A");

PATTERN 9 — Async Inside Timeout

setTimeout(async () => {
  console.log("T1");
  await 0;
  console.log("A1");
});
console.log("A");

PATTERN 10 — Microtask Explosion (Important)

Promise.resolve().then(() => {
  console.log("P1");
  return Promise.resolve().then(() => console.log("P2"));
}).then(() => console.log("P3"));
console.log("A");

PATTERN 11 — Interwoven Async Functions

async function x() {
  console.log("X1");
  await y();
  console.log("X2");
}
async function y() {
  console.log("Y1");
  await null;
  console.log("Y2");
}
console.log("A");
x();
console.log("B");

PATTERN 12 — The Full Combo (Everything Together)

console.log("S");

setTimeout(() => console.log("T1"));

async function f() {
  console.log("F1");
  await Promise.resolve().then(() => console.log("P1"));
  console.log("F2");
}

f();

Promise.resolve().then(() => console.log("P2"));

setTimeout(() => {
  console.log("T2");
  Promise.resolve().then(() => console.log("P3"));
});

console.log("E");

For answers checkout my github link - https://github.com/vaishdwivedi1/js-async

Do share any other questions you find interesting!

Learn JS

Part 1 of 1

This is complete javascript tutorial.