The Event Loop — Predict the OUTPUT ORDER

Share
The Event Loop — Predict the OUTPUT ORDER
Photo by Jonathan Bayu Raditya / Unsplash

Questions

1

console.log('A');
setTimeout(() => console.log('B'), 0);
Promise.resolve().then(() => console.log('C'));
console.log('D');

Output order?

Show answer

A, D, C, B
Sync logs A and D. Then the microtask (C) drains before the setTimeout macrotask (B).

2

console.log(1);
setTimeout(() => console.log(2), 0);
console.log(3);

Output order?

Show answer

1, 3, 2
1 and 3 are synchronous; setTimeout callback 2 is a macrotask that runs after the stack clears.

3

console.log('start');
new Promise((resolve) => {
  console.log('executor');
  resolve();
}).then(() => console.log('then'));
console.log('end');

Output order?

Show answer

start, executor, end, then
The Promise executor runs synchronously (so executor prints between start and end); .then is a microtask, so then runs last.

4

setTimeout(() => console.log('timeout'), 0);
Promise.resolve().then(() => console.log('promise1'));
Promise.resolve().then(() => console.log('promise2'));

Output order?

Show answer

promise1, promise2, timeout
No sync logs. Both microtasks drain (in the order queued) before the single macrotask timeout.

5

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

Output order?

Show answer

1, 5, 3, 2, 4
Sync: 1, 5. Microtask: 3. Then macrotasks fire in registration order: 2, then 4.

6

async function f() {
  console.log('A');
  await null;
  console.log('B');
}
console.log('start');
f();
console.log('end');

Output order?

Show answer

start, A, end, B
f() runs synchronously up to await (prints A), then suspends; end prints. The code after await is a microtask, so B runs after sync code finishes.

7

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

Output order?

Show answer

3, 1, 5, 2, 4
Sync: 3, then f() prints 1 and suspends at await (queues continuation), then 5. Microtasks in queue order: continuation 2, then the standalone .then 4.

8

setTimeout(() => console.log('timeout'), 0);
Promise.resolve().then(() => {
  console.log('promise1');
  queueMicrotask(() => console.log('micro'));
});
console.log('sync');

Output order?

Show answer

sync, promise1, micro, timeout
Sync: sync. Microtask prints promise1 and queues micro during the drain — so micro still runs before the timeout macrotask.

9

console.log('start');
queueMicrotask(() => console.log('micro'));
Promise.resolve().then(() => console.log('promise'));
console.log('end');

Output order?

Show answer

start, end, micro, promise
Sync: start, end. queueMicrotask and .then share the same microtask queue and run in the order they were queued: micro, then promise.

10

console.log('A');
setTimeout(() => {
  console.log('B');
  setTimeout(() => console.log('C'), 0);
}, 0);
setTimeout(() => console.log('D'), 0);
console.log('E');

Output order?

Show answer

A, E, B, D, C
Sync: A, E. Macrotask 1 prints B and schedules C. Macrotask 2 (D) was already queued, so it runs before C. Then C.

11

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

Output order?

Show answer

1, 2, 3
First .then prints 1 and synchronously queues the inner .then (2). The outer chained .then (3) is queued only when the first callback returns, so 2 is queued before 3.

12

async function f() {
  console.log('1');
  await g();
  console.log('2');
}
async function g() {
  console.log('3');
}
setTimeout(() => console.log('4'), 0);
f();
console.log('5');

Output order?

Show answer

1, 3, 5, 2, 4
f() prints 1; await g() runs g synchronously (3) then suspends. Sync 5 prints. Microtask continuation 2 runs before the setTimeout macrotask 4.

13

async function f() {
  console.log('A');
  await null;
  console.log('B');
  await null;
  console.log('C');
}
console.log('start');
f();
Promise.resolve().then(() => console.log('P'));
console.log('end');

Output order?

Show answer

start, A, end, B, P, C
Sync: start, A, end. First continuation B runs, then re-suspends (queues C). P was queued before that re-suspension, so P runs before C.

14

console.log('1');
setTimeout(() => {
  console.log('2');
  Promise.resolve().then(() => console.log('3'));
}, 0);
setTimeout(() => console.log('4'), 0);
Promise.resolve().then(() => console.log('5'));
console.log('6');

Output order?

Show answer

1, 6, 5, 2, 3, 4
Sync: 1, 6. Microtask: 5. Macrotask 1 prints 2, queues 3; microtasks drain (3) before the next macrotask. Macrotask 2: 4.

15

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

Output order?

Show answer

1, 6, 3, 5, 4, 2
Sync: 1, 6. Microtasks: 3 (which returns a thenable) then 5. Returning a Promise adds extra microtask ticks to adopt it, so 4 is delayed until after 5. Macrotask 2 last.

16

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

Output order?

Show answer

a-start, b-start, main, b-end, a-end
a calls b: prints a-start, b-start, then both suspend; main prints. b's continuation prints b-end and resolves b's promise, which then resumes aa-end.

17

console.log('1');
setTimeout(() => console.log('2'), 0);
queueMicrotask(() => {
  console.log('3');
  queueMicrotask(() => console.log('4'));
});
Promise.resolve().then(() => console.log('5'));
console.log('6');

Output order?

Show answer

1, 6, 3, 5, 4, 2
Sync: 1, 6. Microtasks in queue order: 3 (queues 4 during drain), then 5, then the newly queued 4. Macrotask 2 last.

18

async function f() {
  console.log('1');
  setTimeout(() => console.log('2'), 0);
  await Promise.resolve();
  console.log('3');
  await Promise.resolve();
  console.log('4');
}
console.log('5');
f();
setTimeout(() => console.log('6'), 0);
Promise.resolve().then(() => console.log('7'));
console.log('8');

Output order?

Show answer

5, 1, 8, 3, 7, 4, 2, 6
Sync: 5, 1, 8 (the inner setTimeout 2 is queued early but is still a macrotask). Microtasks: 3 (re-suspends, queues 4), 7, then 4. Macrotasks in order: 2, 6.

19

console.log('script start');

setTimeout(() => console.log('setTimeout'), 0);

Promise.resolve()
  .then(() => console.log('promise1'))
  .then(() => console.log('promise2'));

async function async1() {
  console.log('async1 start');
  await async2();
  console.log('async1 end');
}
async function async2() {
  console.log('async2');
}
async1();

console.log('script end');

Output order?

Show answer

script start, async1 start, async2, script end, promise1, async1 end, promise2, setTimeout
Classic. Sync prints the first four. Microtasks: promise1 (queued before async1's continuation), then async1 end, then promise2 (queued when promise1's callback returned). Macrotask setTimeout last.

20

console.log('start');

setTimeout(() => console.log('T1'), 0);

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

new Promise((resolve) => {
  console.log('E');
  resolve();
  console.log('F');
}).then(() => console.log('G'));

setTimeout(() => {
  console.log('T2');
  Promise.resolve().then(() => console.log('H'));
}, 0);

console.log('end');

Output order?

Show answer

start, E, F, end, A, G, B, C, T1, T2, H
Sync: start, executor E/F, end. Microtasks: A (queues B, then its return queues C), G (queued right after A), then B, then C. Macrotask T1, then T2 (which queues H, drained immediately after).