2

In my code below, I would like to execute a, b and c but then a1 since a1 is added within a. However, it doesn't look like Promise.all is updated with the new a1 added. What's the best way to do this? Is there Promise all update? I try not to do await a1 within a.

var arr = [];

async function a() {
  return new Promise(resolve => {
    setTimeout(() => {
    console.log("Resolve a");
    arr.push(a1);
    resolve(1);
    }, 2000);
  });
}

async function b() {
  return new Promise(resolve => {
    setTimeout(() => {
    console.log("Resolve b");
    resolve(2);
    }, 4000);
  });
}

async function c() {
  return new Promise(resolve => {
    setTimeout(() => {
    console.log("Resolve c " + arr.length);
    resolve(3);
    }, 6000);
  });
}

async function a1() {
  return new Promise(resolve => {
    setTimeout(() => {
    console.log("Resolve a1");
    resolve(11);
    }, 2000);
  });
}

arr = [a(), b(), c()];

(async function run() {
  await Promise.all(arr);
})();


console.log('Done');
HP.
  • 19,226
  • 53
  • 154
  • 253
  • 1
    What's the use case for this? You can chain further promises off of `Promise.all` after the fact, but there may be alternative solutions depending on what your *actual* use case is. – zzzzBov Aug 15 '17 at 19:27
  • 1
    What is the point of `(async function run() { await Promise.all(arr); })();`? – Redu Aug 15 '17 at 19:49
  • I have task management (crawl website) function to trigger each task in order. The order is important. – HP. Aug 15 '17 at 20:40
  • possible duplicate of [How to know when all Promises are Resolved in a dynamic “iterable” parameter?](https://stackoverflow.com/q/37801654/1048572)? Also have a look at [Promises for promises that are yet to be created](https://stackoverflow.com/q/37426037/1048572) – Bergi Aug 15 '17 at 21:44
  • "*I try not to do `await a1` within `a`.*" - Why? That's precisely what you should do. – Bergi Aug 15 '17 at 21:47
  • every Promise library I've read does something like `Promise.all = function (arr) { arr = Array.prototype.slice.call(arr);` - so any changes to the original array are irrelevant – Jaromanda X Aug 15 '17 at 23:36
  • @JaromandaX Actually no promise library stores the array of promises. They just loop over the iterable, install fulfillment and rejection handlers on every promise, and count how often they did this. – Bergi Aug 16 '17 at 00:48
  • really @Bergi? I guess I've looked at different promise libraries to you :p – Jaromanda X Aug 16 '17 at 00:53
  • @JaromandaX Yes, really. Storing the array and inspecting every promise to test for settledness would be pretty inefficient. Which promise libraries did you read? – Bergi Aug 16 '17 at 02:01
  • @Bergi - https://github.com/then/promise/blob/master/src/es6-extensions.js#L50 is one example – Jaromanda X Aug 16 '17 at 02:22
  • Others simply use the original array length to do things, so any additions would be ignored – Jaromanda X Aug 16 '17 at 02:30
  • @JaromandaX Ah, [they use `args` to store the results](https://github.com/then/promise/blob/master/src/es6-extensions.js#L78) (overwriting the promises), there's no reason one couldn't start with an empty array and iterate `arr` instead. But the rest of that implementation is not very [ES6y](http://www.ecma-international.org/ecma-262/6.0/#sec-performpromiseall) either. Yes, storing the length is enough. – Bergi Aug 16 '17 at 02:36
  • `the rest of that implementation is not very ES6y` - true, that – Jaromanda X Aug 16 '17 at 02:38

2 Answers2

1

For a start, you push a1 where I think you'd want to push a1() - otherwise you're pushing a function, not a promise

But that won't change anything, because the array passed to Promise.all is (in every library I've seen) copied (using Array#slice) so any changes to the passed in array won't be "visible" to the Promise.all (internal) code

But, you can create a function that recursively calls Promise.all on the array until the length of the results is equal to the (current, new) length of the array

var recursiveAll = a => Promise.all(a).then(r => r.length == a.length ? r : recursiveAll(a));

var arr = [];

async function a() {
  return new Promise(resolve => {
    setTimeout(() => {
    console.log("Resolve a");
    arr.push(a1());
    resolve(1);
    }, 200);
  });
}

async function b() {
  return new Promise(resolve => {
    setTimeout(() => {
    console.log("Resolve b");
    resolve(2);
    }, 400);
  });
}

async function c() {
  return new Promise(resolve => {
    setTimeout(() => {
    console.log("Resolve c " + arr.length);
    resolve(3);
    }, 600);
  });
}

async function a1() {
  return new Promise(resolve => {
    setTimeout(() => {
    console.log("Resolve a1");
    resolve(11);
    }, 200);
  });
}

arr = [a(), b(), c()];

(async function run() {
  let results = await recursiveAll(arr);
  console.log(results);
})();
Jaromanda X
  • 53,868
  • 5
  • 73
  • 87
0

Interesting question...

You may indeed modify Promise.all() on the run by replacing a promise with another one even if the newly inserted one resolves the latest.

In the below example promise three will replace itself with a new promise which will resolve in an additional 2000ms later and Promise.all() will wait until it to resolves to include it's resolving value to the array provided to the .then() stage.

var fun   = _ => new Promise((v,x) => setTimeout(v,2000,5)),
    one   = new Promise((v,x) => setTimeout(v,1000,1)),
    two   = new Promise((v,x) => setTimeout(v,2000,2)),
    three = new Promise((v,x) => setTimeout(v,3000,fun())),
    four  = new Promise((v,x) => setTimeout(v,4000,4));
Promise.all([one,two,three,four])
       .then(a => console.log(a));  

Please wait for 5 seconds to see the result.

Redu
  • 25,060
  • 6
  • 56
  • 76
  • I have thought of this. But the output I want to have is [1,2,3,4,5] where three() returns "3" and trigger fun() which returns "5" and add into the list. This list could go on and on (we basically don't know fun()). – HP. Aug 15 '17 at 20:38
  • @HP. Then i would say, `Promise.all()` must be sequencing the provided array synchronously, of which the items can be re-assigned through referencing in asynchronous timeline while we can not extend itself (the array argument) asynchronously since it's already been processed. You may still be able to splatter new promises to the results but i suspect those new promises can only be processed at the `.then()` stage of `Promise.all()`. I can show it later if that would be fine for your use case. – Redu Aug 15 '17 at 22:03
  • `promise three will replace itself with a new promise` - that's just how promises work, resolving to a Promise, the original promise "adopts" the new promise state - [Point 2.3.2 of the Promise Resolution procedure](https://promisesaplus.com/#point-49) – Jaromanda X Aug 15 '17 at 23:32