# Promises chaining Let's return to the problem mentioned in the chapter : we have a sequence of asynchronous tasks to be done one after another. For instance, loading scripts. How can we code it well? Promises provide a couple of recipes to do that. In this chapter we cover promise chaining. It looks like this: ```js run new Promise(function(resolve, reject) { setTimeout(() => resolve(1), 1000); // (*) }).then(function(result) { // (**) alert(result); // 1 return result * 2; }).then(function(result) { // (***) alert(result); // 2 return result * 2; }).then(function(result) { alert(result); // 4 return result * 2; }); ``` The idea is that the result is passed through the chain of `.then` handlers. Here the flow is: 1. The initial promise resolves in 1 second `(*)`, 2. Then the `.then` handler is called `(**)`. 3. The value that it returns is passed to the next `.then` handler `(***)` 4. ...and so on. As the result is passed along the chain of handlers, we can see a sequence of `alert` calls: `1` -> `2` -> `4`. ![](promise-then-chain.png) The whole thing works, because a call to `promise.then` returns a promise, so that we can call the next `.then` on it. When a handler returns a value, it becomes the result of that promise, so the next `.then` is called with it. To make these words more clear, here's the start of the chain: ```js run new Promise(function(resolve, reject) { setTimeout(() => resolve(1), 1000); }).then(function(result) { alert(result); return result * 2; // <-- (1) }) // <-- (2) // .then… ``` The value returned by `.then` is a promise, that's why we are able to add another `.then` at `(2)`. When the value is returned in `(1)`, that promise becomes resolved, so the next handler runs with the value. **A classic newbie error: technically we can also add many `.then` to a single promise. This is not chaining.** For example: ```js run let promise = new Promise(function(resolve, reject) { setTimeout(() => resolve(1), 1000); }); promise.then(function(result) { alert(result); // 1 return result * 2; }); promise.then(function(result) { alert(result); // 1 return result * 2; }); promise.then(function(result) { alert(result); // 1 return result * 2; }); ``` What we did here is just several handlers to one promise. They don't pass the result to each other, instead they process it independently. Here's the picture (compare it with the chaining above): ![](promise-then-many.png) All `.then` on the same promise get the same result -- the result of that promise. So in the code above all `alert` show the same: `1`. In practice we rarely need multiple handlers for one promise. Chaining is used much more often. ## Returning promises Normally, a value returned by a `.then` handler is immediately passed to the next handler. But there's an exception. If the returned value is a promise, then the further execution is suspended until it settles. After that, the result of that promise is given to the next `.then` handler. For instance: ```js run new Promise(function(resolve, reject) { setTimeout(() => resolve(1), 1000); }).then(function(result) { alert(result); // 1 *!* return new Promise((resolve, reject) => { // (*) setTimeout(() => resolve(result * 2), 1000); }); */!* }).then(function(result) { // (**) alert(result); // 2 return new Promise((resolve, reject) => { setTimeout(() => resolve(result * 2), 1000); }); }).then(function(result) { alert(result); // 4 }); ``` Here the first `.then` shows `1` returns `new Promise(…)` in the line `(*)`. After one second it resolves, and the result (the argument of `resolve`, here it's `result*2`) is passed on to handler of the second `.then` in the line `(**)`. It shows `2` and does the same thing. So the output is again 1 -> 2 -> 4, but now with 1 second delay between `alert` calls. Returning promises allows us to build chains of asynchronous actions. ## Example: loadScript Let's use this feature with the promisified `loadScript`, defined in the [previous chapter](/promise-basics#loadscript), to load scripts one by one, in sequence: ```js run loadScript("/article/promise-chaining/one.js") .then(function(script) { return loadScript("/article/promise-chaining/two.js"); }) .then(function(script) { return loadScript("/article/promise-chaining/three.js"); }) .then(function(script) { // use functions declared in scripts // to show that they indeed loaded one(); two(); three(); }); ``` This code can be made bit shorter with arrow functions: ```js run loadScript("/article/promise-chaining/one.js") .then(script => loadScript("/article/promise-chaining/two.js")) .then(script => loadScript("/article/promise-chaining/three.js")) .then(script => { // scripts are loaded, we can use functions declared there one(); two(); three(); }); ``` Here each `loadScript` call returns a promise, and the next `.then` runs when it resolves. Then it initiates the loading of the next script. So scripts are loaded one after another. We can add more asynchronous actions to the chain. Please note that code is still "flat", it grows down, not to the right. There are no signs of "pyramid of doom". Please note that technically we can add `.then` directly to each `loadScript`, like this: ```js run loadScript("/article/promise-chaining/one.js").then(script1 => { loadScript("/article/promise-chaining/two.js").then(script2 => { loadScript("/article/promise-chaining/three.js").then(script3 => { // this function has access to variables script1, script2 and script3 one(); two(); three(); }); }); }); ``` This code does the same: loads 3 scripts in sequence. But it "grows to the right". So we have the same problem as with callbacks. People who start to use promises sometimes don't know about chaining, so they write it this way. Generally, chaining is preferred. Sometimes it's ok to write `.then` directly, because the nested function has access to the outer scope. In the example above the most nested callback has access to all variables `script1`, `script2`, `script3`. But that's an exception rather than a rule. ````smart header="Thenables" To be precise, `.then` may return an arbitrary "thenable" object, and it will be treated the same way as a promise. A "thenable" object is any object with a method `.then`. The idea is that 3rd-party libraries may implement "promise-compatible" objects of their own. They can have extended set of methods, but also be compatible with native promises, because they implement `.then`. Here's an example of a thenable object: ```js run class Thenable { constructor(num) { this.num = num; } then(resolve, reject) { alert(resolve); // function() { native code } // resolve with this.num*2 after the 1 second setTimeout(() => resolve(this.num * 2), 1000); // (**) } } new Promise(resolve => resolve(1)) .then(result => { return new Thenable(result); // (*) }) .then(alert); // shows 2 after 1000ms ``` JavaScript checks the object returned by `.then` handler in the line `(*)`: if it has a callable method named `then`, then it calls that method providing native functions `resolve`, `reject` as arguments (similar to executor) and waits until one of them is called. In the example above `resolve(2)` is called after 1 second `(**)`. Then the result is passed further down the chain. This feature allows to integrate custom objects with promise chains without having to inherit from `Promise`. ```` ## Bigger example: fetch In frontend programming promises are often used for network requests. So let's see an extended example of that. We'll use the [fetch](mdn:api/WindowOrWorkerGlobalScope/fetch) method to load the information about the user from the remote server. The method is quite complex, it has many optional parameters, but the basic usage is quite simple: ```js let promise = fetch(url); ``` This makes a network request to the `url` and returns a promise. The promise resolves with a `response` object when the remote server responds with headers, but *before the full response is downloaded*. To read the full response, we should call a method `response.text()`: it returns a promise that resolves when the full text downloaded from the remote server, with that text as a result. The code below makes a request to `user.json` and loads its text from the server: ```js run fetch('/article/promise-chaining/user.json') // .then below runs when the remote server responds .then(function(response) { // response.text() returns a new promise that resolves with the full response text // when we finish downloading it return response.text(); }) .then(function(text) { // ...and here's the content of the remote file alert(text); // {"name": "iliakan", isAdmin: true} }); ``` There is also a method `response.json()` that reads the remote data and parses it as JSON. In our case that's even more convenient, so let's switch to it. We'll also use arrow functions for brevity: ```js run // same as above, but response.json() parses the remote content as JSON fetch('/article/promise-chaining/user.json') .then(response => response.json()) .then(user => alert(user.name)); // iliakan ``` Now let's do something with the loaded user. For instance, we can make one more request to GitHub, load the user profile and show the avatar: ```js run // Make a request for user.json fetch('/article/promise-chaining/user.json') // Load it as json .then(response => response.json()) // Make a request to GitHub .then(user => fetch(`https://api.github.com/users/${user.name}`)) // Load the response as json .then(response => response.json()) // Show the avatar image (githubUser.avatar_url) for 3 seconds (maybe animate it) .then(githubUser => { let img = document.createElement('img'); img.src = githubUser.avatar_url; img.className = "promise-avatar-example"; document.body.append(img); setTimeout(() => img.remove(), 3000); // (*) }); ``` The code works, see comments about the details. Although, there's a potential problem in it, a typical error of those who begin to use promises. Look at the line `(*)`: how can we do something *after* the avatar has finished showing and gets removed? For instance, we'd like to show a form for editing that user or something else. As of now, there's no way. To make the chain extendable, we need to return a promise that resolves when the avatar finishes showing. Like this: ```js run fetch('/article/promise-chaining/user.json') .then(response => response.json()) .then(user => fetch(`https://api.github.com/users/${user.name}`)) .then(response => response.json()) *!* .then(githubUser => new Promise(function(resolve, reject) { */!* let img = document.createElement('img'); img.src = githubUser.avatar_url; img.className = "promise-avatar-example"; document.body.append(img); setTimeout(() => { img.remove(); *!* resolve(githubUser); */!* }, 3000); })) // triggers after 3 seconds .then(githubUser => alert(`Finished showing ${githubUser.name}`)); ``` Now right after `setTimeout` runs `img.remove()`, it calls `resolve(githubUser)`, thus passing the control to the next `.then` in the chain and passing forward the user data. As a rule, an asynchronous action should always return a promise. That makes it possible to plan actions after it. Even if we don't plan to extend the chain now, we may need it later. Finally, we can split the code into reusable functions: ```js run function loadJson(url) { return fetch(url) .then(response => response.json()); } function loadGithubUser(name) { return fetch(`https://api.github.com/users/${name}`) .then(response => response.json()); } function showAvatar(githubUser) { return new Promise(function(resolve, reject) { let img = document.createElement('img'); img.src = githubUser.avatar_url; img.className = "promise-avatar-example"; document.body.append(img); setTimeout(() => { img.remove(); resolve(githubUser); }, 3000); }); } // Use them: loadJson('/article/promise-chaining/user.json') .then(user => loadGithubUser(user.name)) .then(showAvatar) .then(githubUser => alert(`Finished showing ${githubUser.name}`)); // ... ``` ## Summary If a `.then` (or `catch/finally`, doesn't matter) handler returns a promise, the rest of the chain waits until it settles. When it does, its result (or error) is passed further. Here's a full picture: ![](promise-handler-variants.png)