Promises
Restaurants
A promise in JavaScript is just a pending task. It’s like ordering food at a restaurant: when you place your order, the server makes a promise to bring the food you ordered. Once the food is brought to the table the promise has been fulfilled. If the food you ordered can’t be served because the kitchen is out of a key ingredient, then you can catch a meal somewhere else.
This is all asynchronous. When you sit down at the table, you might be chatting with a friend or scrolling on your phone. You pause what you were doing so that you can give your order to the server, then return to doing what you were doing beforehand.
JavaScript promises work similarly. Since JavaScript is single-threaded, promises allow the JavaScript engine to move on to other tasks while it waits for certain operations to complete.
JavaScript
A promise is a specific type of object. All promises begin in a pending state. The callback function inside the promise, called an executor, defines when to resolve or reject the promise.
Creating a promise:
const order = new Promise((resolve, reject) => {
if ( foodDelivered) {
resolve('eat food');
} else {
reject('find another restaurant');
}
})
Using a promise
order
// wait for the asynchronous value to be fulfilled
.then(value => console.log(value))
// handle rejection
.catch(error => console.log(error))
.finally(() => console.log('all done'));
Fetch
fetch
is a built-in function in JavaScript that returns a promise. It makes an HTTP request and allows you to handle the response asynchronously with .then()
and .catch()
.
Using fetch()
fetch('url')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.log(error))
.finally(() => console.log('all done');
The Call Stack and Event Loop
The call stack manages synchronous tasks, keeping track of the order in which they execute. This is fairly straightforward: tasks are executed in the order they're written.
However, asynchronous tasks are handled by the event loop. The event loop allows asynchronous code to be executed out of order, letting the JavaScript engine continue working on other tasks without waiting.
Example
How will this execute?
console.log("console log first!");
setTimeout( _ => console.log("set timeout second!"), 0);
Promise.resolve().then(() => console.log("promise third"));
console.log("console log last!!!");
You might expect that it would execute in order, but it doesn’t. The JavaScript event loop processes these instructions differently.
The result is actually this:
> console log first!
> console log last!!!
> promise third
> set timeout second!
Why?
The event loop rearranges the execution priority:
- Synchronous tasks (like console.log("console log first!") and console.log("console log last!!!")) are executed immediately, in the order they appear.
- Microtasks (such as Promise callbacks) are given the next priority and are executed before any other asynchronous tasks.
- Macrotasks (like setTimeout) are handled last, even if the timeout is set to zero.
This allows the JavaScript engine to work asynchronously, performing other tasks without waiting for all operations to complete immediately.
Cover Photo by Andrew Petrov on Unsplash
Top comments (0)