Synchronous, Asynchronous and the Event Loop
JavaScript runs your code on a single thread of execution. It does only one thing at a time: the function currently running sits at the top of the call stack, and the next one waits for it to finish.
function saluer(nom) {
return `Hello ${nom}`;
}
console.log("start");
console.log(saluer("Ada")); // saluer is pushed, executed, then popped
console.log("end");
// Prints: start, Hello Ada, end (in that order)
Why asynchronous?
Waiting for a network response can take a second. If JavaScript blocked the thread during that time, the page would freeze: no more clicks, no more animation. The solution: delegate the waiting to the environment (browser or Node.js) and hand it a function to call back later, a callback.
console.log("A");
setTimeout(() => {
console.log("B"); // runs later, by the event loop
}, 0);
console.log("C");
// Prints: A, C, B
Even with a delay of 0, B is printed last. setTimeout does not run the function: it asks the environment to put it in the task queue once the delay has elapsed.
The event loop
The event loop continuously repeats this cycle:
- run the code in the call stack until it is empty;
- run all pending microtasks (promise continuations,
queueMicrotask); - take one task from the queue (a
setTimeoutcallback, a click event…) and start over.
setTimeout(() => console.log("task"), 0);
Promise.resolve().then(() => console.log("microtask"));
console.log("synchronous");
// synchronous, microtask, task
The setTimeout delay is therefore a minimum, not a guarantee: if the thread is busy with a long computation, the callback will wait.
The callback style
Before promises, asynchronous APIs took a callback, often following the Node.js “error-first” convention:
function lireConfig(callback) {
setTimeout(() => {
const ok = true;
if (!ok) return callback(new Error("File not found"));
callback(null, { theme: "dark" }); // null = no error
}, 10);
}
lireConfig((err, config) => {
if (err) return console.error(err.message);
console.log(config.theme);
});
This style works, but as soon as several operations depend on each other, callbacks nest: this is callback hell. Each level has to handle its own errors, and the code drifts to the right. Promises, covered in the next lesson, solve this problem by representing a future result as an object you can chain.
Key takeaways
- Only one thing at a time on the call stack.
- Waiting is delegated; the continuation comes back through the task queue or the microtask queue.
- Microtasks run before tasks.
Exercises
Solutions and tests stay on the server. In the student space, your code is run and checked, and the tutor gives hints before the solution.
Predict the output order
The
ordre()function must return a promise that resolves with the array of labels in the actual order of execution. Complete the code to record each label injournaland then resolve the promise after the timer.Observe the resulting order: synchronous, microtask, task.
function ordre() { const journal = []; return new Promise((resolve) => { setTimeout(() => { journal.push("timeout"); // TODO : résoudre la promesse avec journal }, 0); Promise.resolve().then(() => journal.push("promesse")); journal.push("synchrone"); }); }The "error-first" convention
Write
diviserPlusTard(a, b, callback)which, after asetTimeoutof 0 ms, calls:callback(new Error("Division par zéro"))ifb === 0;- otherwise
callback(null, a / b).
function diviserPlusTard(a, b, callback) { // TODO }Microtask or task?
What does this code print?
setTimeout(() => console.log('X'), 0); Promise.resolve().then(() => console.log('Y')); console.log('Z');- X, Y, Z
- Z, Y, X
- Z, X, Y
- Y, Z, X
End-of-lesson quiz
How many JavaScript instructions run at the same time on the call stack of a single thread?
- Just one
- As many as there are processor cores
- Two: one synchronous and one asynchronous
What does the delay passed to setTimeout guarantee?
- Execution exactly after that delay
- A minimum delay before the callback can run
- Execution before all promises
What problem does “callback hell” refer to?
- A callback that is never called
- Deeply nested callbacks that make the code unreadable
- A syntax error in setTimeout
The rest of the course
- Promises: Creating, Chaining and Handling Errors18 min
- async/await and try/catch16 min
- Combining Promises: all, allSettled, race, any15 min
- fetch: Consuming a JSON API20 min