Elliot
Elliot

Reputation: 1983

Understanding .then() ES6

I ran into a bug in my code that puzzled me for a long time and am looking for some clarification.

In this code, the commented out inner promise was causing a problem. The Promise.all() at the end was continuing as soon as the setTimeout hit, not after the resolve inside the timeout.

Wrapping the async code with a promise fixes the flow problem, but why is this?

Essentially, why can't we just run normal async code in a .then() chain, an return a Promise.resolve() at the end of the async callback?

var asyncPromise = function() {
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            console.log('Async Promise done');
            resolve();
        }, 1000);
    });
};

var generateSignupPromises = function(qty) {
    var promiseArray = [];
    for (var i = 1; i <= qty; i++) {
        promiseArray.push(
            function() {
                return asyncPromise()
                .then(function() {
                    console.log('Before Timeout');

                  //Uncommenting this fixes the issue
                  //return new Promise(function(resolve, reject) {
                        setTimeout(function() {
                            console.log('After Timeout');
                            //resolve();
                            return Promise.resolve();
                        }, 500);
                  //})
                });
            }
        );
    }
    return promiseArray;
};

var test = generateSignupPromises(1);

Promise.all([test[0]()])
.then(function() {
    console.log('Done');
});

Link to running code: http://www.es6fiddle.net/imfdtuxc/

Upvotes: 2

Views: 2668

Answers (2)

Bergi
Bergi

Reputation: 664307

why can't we just run normal async code in a .then() chain, an return a Promise.resolve() at the end of the async callback?

You perfectly can. But any value - be it a promise or whatever - being returned from a plain asynchronous callback is just ignored as usual.

There is nothing that starting the asynchronous action inside a then callback changes about this, setTimeout just doesn't return a promise - and the then won't know about anything asynchronous happening that it could wait for.

If you want to return a promise from a callback and get another promise for that eventual result, it has to be a then callback:

asyncPromise()
.then(function() {
    return new Promise(function(resolve, reject) {
//  ^^^^^^
        setTimeout(resolve, 500);
    }).then(function() {
//     ^^^^^^^^^^^^^^^
        return Promise.resolve();
    });
});

Upvotes: 5

thangngoc89
thangngoc89

Reputation: 1400

Then is a sync function so if you want to do async task inside then, you has to return a Promise.

Also, Promise.all expect an array of promises. Not an array of an array.

var asyncPromise = function() {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      console.log('Async Promise done');
      resolve();
    }, 1000);
  });
};

var generateSignupPromises = function(qty) {
  var promiseArray = [];
  for (var i = 1; i <= qty; i++) {
    promiseArray.push(
      function() {
        return asyncPromise()
        .then(function() {
          console.log('Before Timeout');

          //Uncommenting this fixes the issue
          return new Promise(function(resolve, reject) {
          setTimeout(function() {
            console.log('After Timeout');
            resolve();
            //return Promise.resolve();
          }, 500);
          })
        });
      }
    );
  }
  return promiseArray;
};

var test = generateSignupPromises(1);

Promise.all([test[0]()])
.then(function() {
  console.log('Done');
});

http://www.es6fiddle.net/imfe2sze/

Upvotes: 0

Related Questions