Callbacks and promises
A callback is a function you hand to other code to call later; a promise is an object that stands for a value that is not ready yet. Follow ten real lines that wrap setTimeout in a promise and chain two .then calls: the script prints start and end at once, and half a second later the promise is fulfilled, its saved callbacks pass through the microtask queue, and the console prints got 1000.
5 quick questions
Pick an answer to see why. Your score saves with your progress.
01What does this script print, in order? console.log("A"); setTimeout(() => console.log("B"), 0); console.log("C");
setTimeout only hands its callback to the timer. The script keeps running and prints C; the callback runs later as a new task, even with a delay of 0.
02Right after new Promise((resolve) => { setTimeout(() => resolve(5), 100); }) runs, what state is the promise in?
The executor runs at once, but it only starts a timer. Until resolve(5) is called about 100 ms later, the promise is pending.
03p.then((x) => x * 2) returns what?
.then always returns a new promise. The callback's return value fulfils it, which is how a chain passes each result to the next step.
04In the figure, p1 has just been fulfilled with 500. When does the callback saved by line 8 run?
Fulfilling a promise queues its saved callbacks as microtasks. The event loop runs every microtask as soon as the current task ends, before it takes another task.
05A promise is rejected. The chain is .then(f).then(g).catch(h). What runs?
A rejection skips .then callbacks that have no rejection handler and passes down the chain to the first .catch, which receives the error.
Glossary
- Callback
- A function you pass to other code, which calls it later, such as the arrow function given to setTimeout or .then.
- Promise
- An object that stands for a value that is not ready yet. It is pending, then settles once: fulfilled with a value or rejected with a reason.
- Pending
- The state of a promise that has not settled yet.
- Fulfilled
- The state of a promise that succeeded; it holds its value, which never changes again.
- Rejected
- The state of a promise that failed; it holds the reason (usually an Error), which .catch receives.
- then
- A promise method that saves a callback to run when the promise is fulfilled, and returns a new promise for the callback's result.
- Microtask queue
- The queue where promise callbacks wait. The event loop empties it after every task, before the next task runs.
- Task
- A unit of work the event loop runs, such as running a script or a timer's callback.
Notes and sources
- p1, p2 and p3 are the figure's names. The script never stores them in variables: wait(500) returns p1, and each .then call returns the next one.
- setTimeout waits at least the delay you give it; a busy page, a background tab or nested timers can make it later. In a browser the timer belongs to the page (the window), in Node.js to its event loop; neither is part of the JavaScript language itself.
- The ECMAScript specification calls a queued promise callback a job (PromiseReactionJob); browsers and Node.js run these jobs as microtasks. After every task, the event loop runs microtasks until the queue is empty, including ones added meanwhile, which is why p2's callback runs before any other task.
- Resolving with another promise (or any object with a then method) makes the outer promise follow it instead of fulfilling with it directly. This example only resolves with plain numbers.
- The script is real. Paste it into a browser console or save it as wait.js and run node wait.js: it prints start, end, and half a second later got 1000.
- MDN: Callback function
- MDN: Promise
- MDN: Promise() constructor
- MDN: Promise.prototype.then()
- MDN: Promise.prototype.catch()
- MDN: Using promises
- MDN: setTimeout()
- MDN: Using microtasks in JavaScript
- MDN: JavaScript execution model
- ECMAScript Language Specification: Promise Objects
- WHATWG HTML Standard: Event loop processing model
Quiz Unlocks after the last step.