Search code examples
javascriptfunctionpromisees6-promise

Promise and Promise.all(array) executed before array fulfilled


The Promise.all(arr).then callback is executed before the array is fulfilled, so it doesn’t catch its elements. How can I do this properly?

var arr = [];

for (var i = 0; i < 2; i++) {
  arr.push((function() {
    new Promise(function(resolve, reject) {
      setTimeout(function() {
        console.log("Resolved!");
        resolve();
      }, 3000);
    });
  })());
}

Promise.all(arr).then(function() {
  console.log("Done");
});

My expect result is:

Resolved!
Resolved!
Done

But real result is:

Done
Resolved!
Resolved!

The code above is just an example. I changed the structure like below and the code no longer has a problem, but I should use a for loop and push because of my application structure.

var p1 = new Promise(function(resolve, reject) {
  setTimeout(function() {
    console.log("Resolved #1");
    resolve();
  }, 1000);
});
var p2 = new Promise(function(resolve, reject) {
  setTimeout(function() {
    console.log("Resolved #2");
    resolve();
  }, 2000);
});
var arr = [p1, p2];

Promise.all(arr).then(function() {
  console.log("Done");
});


Solution

  • As georg said, you're just not putting the promises in arr, because you never return anything from the anonymous function you've wrapped around new Promise. That function is also completely unnecessary, so:

    var arr = [];
    
    for (var i = 0; i < 2; i++) {
      arr.push(new Promise(function(resolve, reject) {
        setTimeout(function() {
          log('resolved !');
          resolve();
        }, 500);
      }));
    }
    
    Promise.all(arr).then(function() {
      log("Done");
    });
    
    function log(msg) {
      var p = document.createElement('p');
      p.appendChild(document.createTextNode(msg));
      document.body.appendChild(p);
    }

    If the function is there so you can capture the then-current value of i, just ensure you return the promise:

    var arr = [];
    
    for (var i = 0; i < 2; i++) {
      arr.push(function(index) {
        return new Promise(function(resolve, reject) {
          setTimeout(function() {
            log('resolved with ' + index + ' !');
            resolve(index);
          }, 500);
        });
      }(i));
    }
    
    Promise.all(arr).then(function() {
      log("Done");
    });
    
    function log(msg) {
      var p = document.createElement('p');
      p.appendChild(document.createTextNode(msg));
      document.body.appendChild(p);
    }