JavaScript Academy · Lesson

Microtasks and Promises

Learn why promise callbacks run first.

Lesson 3 of 413 steps

Microtasks and Promises is a free JavaScript Academy lesson on CoddyKit. This is lesson 3 of 4. Any 3 lessons of this learning path are free to read in full — after that, CoddyKit PRO unlocks every lesson, plus hands-on practice with a built-in code editor and a 24/7 AI tutor. It is part of the JavaScript Academy learning path, and your progress syncs across the web and the CoddyKit app. The JavaScript Academy course includes 4 lessons in total.

What Is a Microtask?

A microtask is a high-priority deferred job. Promise callbacks (.then, .catch, .finally) and queueMicrotask all schedule microtasks.

The key rule: after each synchronous run, all microtasks drain before any macrotask.

Promise Callbacks Are Deferred

Even an already-resolved Promise schedules its .then callback as a microtask. It does not run synchronously.

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

Microtasks Beat Macrotasks

This is the most important ordering rule. A Promise callback runs before a setTimeout callback, even if the timer was scheduled first.

setTimeout(() => console.log('timeout (macro)'), 0);
Promise.resolve().then(() => console.log('promise (micro)'));
console.log('sync');

The Microtask Queue Drains Fully

The event loop empties the entire microtask queue before taking the next macrotask. Multiple Promise callbacks all run together in that drain.

setTimeout(() => console.log('macro'), 0);
Promise.resolve().then(() => console.log('micro 1'));
Promise.resolve().then(() => console.log('micro 2'));
console.log('sync');

Chained Promises

Each .then in a chain schedules a new microtask when the previous one settles. They still all run before any pending timer.

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

Microtasks Scheduled During Drain

If a microtask schedules another microtask, the new one also runs in the same drain, before any macrotask. The queue keeps emptying until truly empty.

Promise.resolve().then(() => {
  console.log('micro A');
  Promise.resolve().then(() => console.log('micro B (added later)'));
});
setTimeout(() => console.log('macro'), 0);
console.log('sync');

Resolved Values Flow Through

A value returned from a .then handler becomes the input to the next handler in the chain, all via microtasks.

Promise.resolve(2)
  .then(n => n * 3)
  .then(n => n + 1)
  .then(n => console.log('result', n));
console.log('sync first');

async/await Uses Microtasks

Code after an await resumes as a microtask. So an awaited continuation runs before a timer scheduled earlier.

async function run() {
  console.log('a');
  await null;
  console.log('c (after await)');
}
setTimeout(() => console.log('d (timeout)'), 0);
run();
console.log('b');

A Combined Ordering Demo

Put it all together. Predict the order: synchronous first, then all microtasks, then the macrotask.

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

Why Microtask Starvation Is Risky

Because microtasks always run before macrotasks, a microtask that endlessly schedules more microtasks can starve timers and rendering. Keep microtask chains finite.

let n = 0;
function loop() {
  if (n++ < 3) {
    console.log('micro ' + n);
    Promise.resolve().then(loop);
  }
}
setTimeout(() => console.log('macro after micros'), 0);
loop();

Why This Ordering Matters

Knowing microtasks run before macrotasks explains why Promise results appear before timer callbacks and why ordering bugs happen. The rule is simple: sync, then drain all microtasks, then one macrotask, repeat.

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

Quick Check

A Promise .then and a setTimeout(fn, 0) are both pending. Which runs first?

Recap: Microtasks and Promises

You learned the priority rule:

  • Microtasks come from Promises and queueMicrotask.
  • The whole microtask queue drains before any macrotask.
  • async/await continuations are microtasks.
  • Endless microtask chains can starve timers and rendering.
Free to start

Learn JavaScript with an AI tutor — free

Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.

Courses
59
Lessons
200

Frequently Asked Questions

Is the “Microtasks and Promises” lesson free?

Yes — any 3 lessons of the JavaScript Academy learning path, including “Microtasks and Promises”, are free to read in full here on the web. After that, CoddyKit PRO unlocks every lesson, plus interactive practice with a built-in code editor and a 24/7 AI tutor. The JavaScript Academy course includes 4 lessons in total.

What will I learn in “Microtasks and Promises”?

Learn why promise callbacks run first. You practise JavaScript Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start JavaScript Academy?

No prior experience is required. JavaScript Academy on CoddyKit is structured for beginners through advanced learners, so you can start here or from the beginning and move at your own pace. This is lesson 3 of 4.

How long does the “Microtasks and Promises” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this JavaScript Academy lesson?

Yes. Every JavaScript Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. The Call Stack
  2. Macrotasks and the Task Queue
  3. Microtasks and Promises
  4. queueMicrotask and Ordering
← Back to JavaScript Academy