Ivan Jouikov
Ivan Jouikov

Reputation: 21

Why does JS Promise .then() evaluate before resolve()

I've been playing with Promises and I put together the following code that isn't acting like I'm expecting it to. You can run it in a Fiddle here:

https://fiddle.sencha.com/#view/editor&fiddle/1pmk

function log(txt) {
  var lapsed = new Date().getTime() - START;
  console.log(lapsed, txt);
}
START = new Date().getTime();

var promise = new Promise(function promiseExecutor(resolve, reject) {
  log('in Promise 1 Executor');
  setTimeout(function onSetTimeout() {
    log('in Promise 1 Timeout');
    resolve(123);
  }, 500);
});

var promise2 = new Promise(function promise2Executor(resolve, reject) {
  log('in Promise 2 Executor');
  setTimeout(function onSetTimeout() {
    log('in Promise 2 Timeout');
    resolve(123);
  }, 1000);
});

// sequence
promise
  .then(promise2)
  .then(function onPromiseDone(p) {
    // TODO: why this executes before promise2 resolve?
    log('ALL Promise Done! ' + p);
  });

If you watch the Console, you'll notice that the "ALL Promise Done" message is fired immediately after the FIRST promise is resolved, and then half a second later the 2nd promise is resolved...

How is it possible that the final then(onPromiseDone) is fired without resolve()?

Now, I understand that the Promise executor function starts running immediately, and this here is not a good example for "sequencing". I am able to achieve the correct behavior by wrapping my promises in "deferred" functions as shown here:

https://fiddle.sencha.com/#view/editor&fiddle/1pml

Still, this doesn't answer my question for the original fiddle, which I'll repeat:

How is it possible that the final then(onPromiseDone) is fired without resolve()?

Thanks!

Upvotes: 0

Views: 4097

Answers (1)

luiscrjr
luiscrjr

Reputation: 7258

.then receives two arguments: a function that triggers when the Promise successfully resolves and a function that's invoked when the Promise is rejected (can be ommited).

In your example, you're passing a new promisse as an argument.

In order to achieve your goal (chain), I suggest something like that:

var promise = new Promise(function (resolve, reject) {
  log('in Promise 1 Executor');
  setTimeout(function onSetTimeout() {
    log('in Promise 1 Timeout');
    resolve(123);
  }, 2000);
});


var callback = function(val) {
  log('received from the first promisse: ' + val)
  return new Promise(function (resolve, reject) {
    log('in Promise 2 Executor');
    setTimeout(function onSetTimeout() {
      log('in Promise 2 Timeout');
      resolve(456);
    }, 2000);
  });
}


// Promise.all([promise, promise2]) // parallelize
// sequence
promise
  .then(callback)
  .then(function(val) {
        log('received from the second promisse: ' + val)
        log('ALL Promise Done! ');
    }
  );

This way, you run your promisse and set the callback function as .then parameter. So, just when the first setTimeout finishes, it will call resolve and invoke callback function, that will create a new Promise and then set the new setTimeout.

Will output:

0 "in Promise 1 Executor"
2002 "in Promise 1 Timeout"
2002 "received from the first promisse: 123"
2002 "in Promise 2 Executor"
4002 "in Promise 2 Timeout"
4003 "received from the second promisse: 456"
4003 "ALL Promise Done! "

Working fiddle: https://jsfiddle.net/mrlew/L8b8fow9/

Edited after @Bergi's comment. Thanks.

Upvotes: 1

Related Questions