Skip to main content

JavaScript Promises & Async/Await Simulator

Visualize JavaScript promises, async/await, microtasks, task queues, setTimeout ordering, rejection handling, and Promise.all with an interactive event-loop simulator inspired by classic JavaScript visual guides.

Category: Programming

Topics covered: javascript, promises, async-await, event-loop, microtasks, settimeout, nodejs, programming, frontend, backend, educational, interactive

// simulator

JavaScript Promises & Async/Await Simulator

Visualize JavaScript promises, async/await, microtasks, task queues, setTimeout ordering, rejection handling, and Promise.all with an interactive event-loop simulator inspired by classic JavaScript visual guides.

Supported byBecome a sponsor
BitriseAtomsizedDigitalOceanDevDojoSMTPfastQuizAPI

// event loop lab

JavaScript Promises & Async/Await Simulator
step 1/6
1/6

Start in global execution

stack

The script begins on the call stack. Nothing async has been scheduled yet.

async-lab.js
1console.log('Start');
2
3setTimeout(() => console.log('Timeout'), 0);
4
5Promise.resolve('Promise').then(value => {
6 console.log(value);
7});
8
9console.log('End');
Mental model
1Run stack first.
2Drain microtasks before tasks.
3Timers and I/O wait as tasks.
4await resumes as a microtask.

Runtime state

Read the phase rail first, then inspect the boxes below for what changed.

stack
You are here: Stack - Normal code runs first.
1Stack

Normal code runs first.

2Runtime

Timers wait outside JS.

3Promise

Promise state changes.

4Microtask

Promise callbacks run next.

5Task

Timers run after microtasks.

6Console

Logs appear in order.

Call Stack
2
global script
console.log('Start')
Runtime APIs
0
no external work
Promise Inspector
2
Promise.resolve: not created
value: -
Microtask Queue
0
no promise work queued
Task Queue
0
no timer or event tasks
Console
1
1. Start
Predict It

What gets printed first after Start?

About this JavaScript async simulator

What you'll learn

  • Why synchronous code runs before promise callbacks and timers
  • How fulfilled, rejected, and pending promise states affect handler execution
  • Why promise callbacks are microtasks, while timers are tasks
  • How async functions run until await and then resume later
  • How catch and finally behave after a promise rejection
  • How Promise.all waits for several async operations at once

Visual model covered

  • Call stack: currently executing synchronous JavaScript
  • Runtime APIs: timers, network work, and other browser or runtime-owned async work
  • Microtask queue: promise handlers, queueMicrotask callbacks, and async function continuations
  • Task queue: timer and event callbacks that run after microtasks drain

Inspired by a classic visual guide

This simulator is an original interactive companion inspired by Lydia Hallie's popular JavaScript visualized article on promises and async/await. It uses its own diagrams and step logic while covering the same core mental models.

Browser-safe by design

The simulator does not execute arbitrary JavaScript. Each scenario is modeled as a deterministic event-loop trace so learners can step backward, make predictions, and see exactly why the output order changes.

Overview

JavaScript runs on one thread, so async code is about the order in which callbacks get their turn. This simulator makes that order visible. It shows the call stack, the runtime where timers wait, the promises, the microtask queue, the task queue and the console, and steps through short programs one action at a time. The first scenario shows why microtasks beat timers: a promise callback runs before a setTimeout callback with a zero delay, because the microtask queue drains completely before the next task starts. The second shows what await really does: the async function runs synchronously until the first await, then pauses while the outer script keeps going, and resumes later as a microtask. The third follows a rejected promise as it skips to catch while synchronous code still runs, with finally running for cleanup. The last shows Promise.all waiting for every input before it resolves. Once you can predict the console output, async bugs such as unexpected ordering become much easier to reason about.

Try this

  1. Step through "Microtasks beat timers" and predict the console order before each step.
  2. Play "Await suspends the function" and watch run() pause at await while the outer script keeps logging.
  3. Open "Rejections jump to catch" to see the rejection skip ahead to catch and finally run last.

Frequently asked questions

Why does a promise callback run before setTimeout with 0 ms?
Promise callbacks are microtasks, and the event loop drains the whole microtask queue before it takes the next task. setTimeout callbacks are tasks, so they wait until the microtasks are done.
Does await block the thread?
No. await pauses only the async function it is in. The rest of the program keeps running, and the function resumes as a microtask when the awaited promise settles.
What happens if one promise in Promise.all rejects?
Promise.all rejects immediately with that reason and ignores the results of the others. Use Promise.allSettled when you need every result regardless of failures.

Try next

Sponsored
Carbon Ads
$ cd /games
// share