0

So I'm trying to grasp Promises and as of now I think I'm understanding everything I've read so far except for one example listed on MDN Web Docs (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then) which I modified.

Original goes like this:

Promise.resolve('foo')
  // 1. Receive "foo" concatenate "bar" to it and resolve that to the next then
  .then(function(string) {
    return new Promise(function(resolve, reject) {
      setTimeout(function() {
        string += 'bar';
        resolve(string);
      }, 1);
    });
  })
  // 2. receive "foobar", register a callback function to work on that string
  // and print it to the console, but not before return the unworked on
  // string to the next then
  .then(function(string) {
    setTimeout(function() {
      string += 'baz';
      console.log(string);
    }, 1)
    return string;
  })
  // 3. print helpful messages about how the code in this section will be run
  // before string is actually processed by the mocked asynchronous code in the
  // prior then block.  
  .then(function(string) {
    console.log("Last Then:  oops... didn't bother to instantiate and return " +
                "a promise in the prior then so the sequence may be a bit " +
                "surprising");

    // Note that `string` will not have the 'baz' bit of it at this point. This 
    // is because we mocked that to happen asynchronously with a setTimeout function
    console.log(string);
});

Which indeed was surprising, but eventually understood (well, at least I think I understood) why it happened that way.

Now, I changed the second .then to:

  .then(function(string) {
    setTimeout(function() {
      string += 'baz';
      console.log(string);
      return string;
    }, 1)

And I'm getting that the last .then is being executed before the second .then returns a value. According to the MDN, "When a value is simply returned from within a then handler, it will effectively return Promise.resolve()." Shouldn't the next .then wait for it to Resolve or Reject (which implies waiting for the Timeout callback to execute) in order to execute?

Let me say sorry in advance if I'm missing something obvious or my question is dumb. And thank you!

  • Yeah, the quote from MDN is right. In your modified example it's just returning undefined to be passed to the next then. – Andrew Li Nov 25 '17 at 22:30
  • That's what I don't understand. Why is it returning a value (and apparently resolving the promise) before I explicitly told it to return anything? – Agustin Lleras Nov 25 '17 at 22:33
  • Because `setTimeout` is asynchronous. Execution continues before it finishes, thus the end of the function is reached before `setTimeout` finishes. You aren't explicitly returning anything so undefined is returned to the next then. – Andrew Li Nov 25 '17 at 22:34
  • The best way i found to 'reason' about Promises is to think of a Promise as the same as a normal Object that is passed around "synchronously" and can be passed to functions or returned from functions, but with the caveat that any time you "use" the "value" the promise holds, you simply stick it in a 'then'. Don't try to ever know WHEN the 'thens' will actually be executing because it's all async and unpredictable to in some sense. –  Nov 25 '17 at 23:14
  • Yes, I'm starting to agree with you. I always have to find a way to reason with stuff. Will read this several times until I feel comfortable with it. Thanks! – Agustin Lleras Nov 26 '17 at 01:46

2 Answers2

3

And I'm getting that the last .then is being executed before the second .then returns a value.

No. You just didn't see where the second then returns the value. Your return statement is within the setTimeout callback and returns from that function (later), it does not return from the then callback. That function in fact doesn't have any return statement, so by default it returns undefined after executing the body.

You're basically doing

.then(function(string) {
  setTimeout(function() {
    string += 'baz';
    console.log(string);
    return string; // irrelevant for the promise chain
  }, 1)
  return undefined; // this is the value that the promise resolves with
//       ^^^^^^^^^     and which the next `then` callback receives
})
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Thank you. I had guessed it was that way but I wasn't really digesting it. Also I did fail to see the scope of that return. I think the best way of making the next then execute after the timeout is to insert it in a promise, right? – Agustin Lleras Nov 26 '17 at 01:45
  • Yes, you need to return a promise from the `then` callback. – Bergi Nov 26 '17 at 11:15
-1

I think the return in the setTimeout is confusing you. I think you might need to use resolve() instead. See Get return value from setTimeout

The second "then()" should immediately return - it won't wait for an async setTimeout to resolve the "string" when it can just return what was passed into it immediately.

You're effectively doing:

.then(function(string) {
  return;
})


setTimeout(function() {
  string += 'baz';
  console.log(string);
  return string;
}, 1)
jjj
  • 126
  • 1
  • 4