1

I'm trying to run a list of functions synchronously after a loop using promise.all() but my code doesn't work as expected.

Does someone know what I did wrong?

my code is :

var Promise = require('promise');
var promises = [];

for (var i = 0; i < 3; i++) {
    console.log('push promise ' + i);
    promises.push(foo(i));
}

Promise.all(promises)
        .then(function (data) {
            console.log("done");
        });

function foo(i) {
    return new Promise(function (resolve, reject) {
        console.log('---> foo i ' + i);
        resolve('done foo ' + i);

    });
}

but the output is

push promise 0
---> foo i 0
push promise 1
---> foo i 1
push promise 2
---> foo i 2
done

where I expect

push promise 0
push promise 1
push promise 2
---> foo i 0
---> foo i 1
---> foo i 2
done

Thank you in advance.

Tom Ines
  • 103
  • 1
  • 7
  • 1
    All promises start resolving when they are created. Calling `Promise.all` simply creates another promise that resolves when all of its arguments resolve. Notice that there is no asynchronous behaviour in your constructor function. You can use [setTimeout(..., 0)](https://stackoverflow.com/questions/1360238/myfunction-vs-window-settimeoutmyfunction-0) to achieve the execution order you expect. – allonhadaya Nov 17 '17 at 05:05

3 Answers3

2

What's happening here is that when you call the promise constructor, the function being passed to it is being invoked during the construction call. If you had async call being inside the promise (which is the intended use case), then it would create the behaviour you were expecting.

Here is my example code, using setTimeout as the async call, and note how the resolve call is made inside the async callback.

var promises = [];

for (var i = 0; i < 3; i++) {
    console.log('push promise ' + i);
    promises.push(foo(i));
}

Promise.all(promises)
        .then(function (data) {
            console.log("done");
        });

function foo(i) {
    return new Promise(function (resolve, reject) {
        // The async call is made inside the Promise
        setTimeout(()=> {
            console.log('---> foo i ' + i);
            // And the resolve call is made inside the callback function
            resolve('done foo ' + i);
        });
    });
}

If you run this, you should get the output you desired (tested in chrome):

push promise 0
push promise 1
push promise 2
---> foo i 0
---> foo i 1
---> foo i 2
done

Addendum: This only works (foo i 0, ... 1 ... 2 are in order) because the requests are all done immediately one after the other. If it was an ajax call, the foo statements would be printed in order of completion. So if request 2 finished before 0 or 1, you would see foo i 2 first. But done will only be visible when all the requests were resolved.

Kaiser Dandangi
  • 230
  • 2
  • 8
0

I'm trying to run a list of functions synchronously after a loop using promise.all() but my code doesn't work as expected.

I think you want run a list of functions synchronously. If so, I recommend to use Bluebird Promise.each().

var Promise = require('bluebird');
var promises = [];

for (var i = 0; i < 3; i++) {
    console.log('push promise ' + i);
    promises.push(foo(i));
}

Promise.each(promises, function(result) {
    console.log(result);
});

function foo(i) {
    return new Promise(function (resolve, reject) {
        resolve('done foo ' + i);
    });
}

Results:

push promise 0
push promise 1
push promise 2
done foo 0
done foo 1
done foo 2
ebo
  • 2,717
  • 1
  • 27
  • 22
-1

Your console.log('---> foo i ' + i); line is being executed on promise creation as it's outside of the resolve method, and instead inside the executor function that you supplied to the Promise constructor.

This should give you your expected output

var Promise = require('promise');
var promises = [];

for (var i = 0; i < 3; i++) {
    console.log('push promise ' + i);
    promises.push(foo(i));
}

Promise.all(promises)
        .then(function (data) {
          for (var i = 0; i < data.length; i++) {
            console.log(data[i]);
          }         
            console.log("done");
        });

function foo(i) {
    return new Promise(function (resolve, reject) {
      resolve('--> foo i ' + i);
    });
}
Daniel Bernsons
  • 650
  • 7
  • 20
  • Outside of the `resolve` callback? There is no `resolve` callback. – Charlie Fish Nov 17 '17 at 05:01
  • He probably means the executor function passed to the `Promise` constructor. – rossipedia Nov 17 '17 at 05:03
  • Correct, I used the wrong terminology. It's late on Friday afternoon here, apologies. I'll fix it up. – Daniel Bernsons Nov 17 '17 at 05:04
  • @DanielBernsons I also don't think your answer addresses his question. I think he is wondering why the code within that promise function is being run when pushing to the array. Sometimes you do want to have code that is only run when the Promise is run, not on creation almost. – Charlie Fish Nov 17 '17 at 05:05
  • @CharlieFish sure sometimes you do, but that was not what was asked. He simply wanted to know why the `---> foo i` lines were not being executed in `Promise.all`, which my answer covers. – Daniel Bernsons Nov 17 '17 at 05:15