Practice using promises to avoid "callback hell" in asynchronous JavaScript
Running functions in sequence (one after another) is a common requirement. For example, triggering animations in order, or requesting some data then sending that response on to another API.
If your code is synchronous it's easy to make it run in order: that's what JavaScript does automatically. Each line of code runs one by one:
However once you have asynchronous code this gets harder to manage. You don't know how long each bit of code will take, so you have to make sure each line of code waits for the previous one.
However this quickly gets difficult to manage as each new callback introduces another level of nesting.
Promises make it easier to run code in sequence. A promise object's .then method returns a new promise that resolves with whatever value you returned from the callback you passed in.
Here we have a promise that will eventually resolve with the value 1:
We can access this value using the promise's .then method:
Since .then returns a new promise we can assign it to a variable and use it again:
Here we wait for onePromise to resolve with 1, then multiply that by 5 and return the result. This creates a new promise that will eventually resolve with 5. We can then access this value by using the .then method of this second promise.
Since each .then returns a new promise object we can avoid all the extra variables and chain the .then methods directly:
This example is a bit silly since multiplication is synchronous—we can just use value * 5 directly without the second then. However since .thens always return new promises we can chain asynchronous operations together to avoid nesting our callbacks.
Imagine we had another function that multiplied numbers after 2 seconds:
Here we're starting to recreate our "callback hell" from the traffic lights example. Each new asynchronous operation means nesting a callback one level deeper.
However since each .then returns a promise we can return our fivePromise promise and access in it the next.then:
Since all we do with the fivePromise variable is return it we can skip defining it and simplify our code to:
The magic part is that we can return sync or async operations from a .then—promise objects don't care what kind of value is inside them. The next .then in the chain will always wait for the previous value to be ready.
Challenge 1: traffic lights again
You're going to recreate the traffic lights from the callback workshop, but using promises to avoid nesting your callbacks.
Download the starter files and open challenge-1/index.html
The pre-defined wait function is like setTimeout, except it returns a promise that resolves after waiting the specified number of milliseconds
Try not to let your callbacks go beyond a single level of nesting!
resolvesWithOne() // <- returns a promise that resolves with 1
.then((value) => value * 5) // <- returns a promise that resolves with (1 * 5)
.then((value) => console.log(value)); // <- returns a promise that resolves with undefined
// Logs 5 (eventually)