Need Help With Promise Chaining

So, I understand that .then() returns a new Promise that can be chained to another .then().

The following example, though, has me confused. This tutorial is saying that the final .then() in the example cannot be extended unless it explicitly returns a new Promise.

// 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
  .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); // (*)
  });

They are saying that the final .then() cannot be extended, and that it has to be written to explicitly return a new Promise, like this:

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(`Showed ${githubUser.name}`));

Could someone please explain to me why all the other instances of .then() we could chain without having to explicitly return a new Promise, but why with that last one we couldn’t?

Thank you.

Hi Josephylee, can you post the challenge seed, not sure what you confused with?

@Notchoaveragejoe

https://javascript.info/promise-chaining

At the end of the page, the section titled Bigger Example: fetch.

They have a chain of .then() statements, and they chain just fine even though none of them explicitly return a new Promise. Then for the last .then(), the example says that it needs to return a new Promise in order to chain another .then().

Hello!

That’s because fetch() and response.json() already return a promise.

However, every chained then will execute unless there’s an error (when the promise is rejected). Look a this example:

function log(msg) {
  console.log(msg);
}

fetch('https://jsonplaceholder.typicode.com/todos/1')
  .then(response => response.json())
  .then(json => {
    log('Todo 1: ' + JSON.stringify(json))
    return 'afterTodo';
  })
  .then(val => log('After TODO: ' + val))
  .then(() => log('Last one'));

Here, every then will be called, even when you don’t explicitly return a value.

The reasoning here is that you’re doing something after the timer runs out:

setTimeout(() => img.remove(), 3000);

The instruction img.remove() would be executed after 3 seconds (3000 milis), but at that point the next instruction would have already been executed, thus the next then would not receive a parameter. You could chain another then, but with a void parameter (just like my previous example).

In other words, you would need to use a promise to let the next then know you finished executing your instructions asynchronously.

Let me know if that helps :slight_smile:

1 Like

@skaparate

Awesome! Yes, that helps a bunch. Thank you for your response.

1 Like