Home > Net >  Is there a promise function in javascript that is similar to array.some?
Is there a promise function in javascript that is similar to array.some?

Time:04-30

I see a bunch of promise functions like here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/race

but is there some function I can use that is similar to the array.prototype.some function? Something like this

var promises = [...]; // this is an array of promises
var containsTrue = await Promise.some(promises, x => x); 

Resolves as true as soon as any of the promises resolves with true. Resolves as false if all resolve as false.

If any promise rejects, it rejects immediately.

Does anyone know best way to implement this?

CodePudding user response:

You can combine Promise.any with an additional handler that throws if the value isn't true (or truthy, whatever logic you need).

await Promise.any(
  promises.map(promise => promise.then(
    (result) => {
      if (!result) throw new Error(); // Make this reject
    }
  ))
);
// will reject if all promises reject

CodePudding user response:

Asssuming the spec is this:

  1. Resolve immediately with the value of true as soon as any of the promises resolves as true.
  2. Resolve with the value of false if all the promises resolve to false.
  3. Reject immediately if any of the promises rejects.

Then, there is no specific built-in promise function that does that. Neither Promise.race() nor Promise.any() matches that perfectly.

The problem with both Promise.race() and Promise.any() is that they both resolve as soon as any promise you've given them resolve. They don't look for the resolved value to be true. Per your spec, if a promise resolves to false, you want to keep waiting for another one to possibly resolve to true. That, by definition, won't work with Promise.race() because it finishes whenever the first promise resolves or rejects which is just not what you want.

Promise.any() could be partially made to work by artificially changing a promise that resolves to false into a temporary rejection, but somehow keep track of whether it actually rejected or we just faked a rejection to keep Promise.any() from finishing. But, there is no way to tell it to stop immediately when you get a real rejection because its design is to keep going until the end look for any promise that resolves, ignoring rejections unless they all reject.

So, Promise.race() stops too quickly when you want it to keep looking and Promise.any() won't stop quickly when you want it to.

So, here's how you can build your own implementation:

function PromiseSome(iterable) {
    return new Promise((resolve, reject) => {
        let len = 0;
        let doneCnt = 0;
        for (let p of iterable) {
              len;
            Promise.resolve(p).then(result => {
                  doneCnt;
                if (result === true) {
                    resolve(true);
                } else {
                    // if done with all of them
                    if (doneCnt === len) {
                        resolve(false);
                    }
                }
            }).catch(reject);
        }
    });
}

Or, if you want to ignore all rejections (just treat them the same as resolving false), then you can do this:

function PromiseSome(iterable) {
    return new Promise((resolve, reject) => {
        let len = 0;
        let doneCnt = 0;
        for (let p of iterable) {
              len;
            Promise.resolve(p).catch(err => {
                // treat any rejection as just resolving false
                return false;
            }).then(result => {
                  doneCnt;
                if (result === true) {
                    resolve(true);
                } else {
                    // if done with all of them
                    if (doneCnt === len) {
                        resolve(false);
                    }
                }
            });
        }
    });
}

Note, these are designed to look for the EXACT result of true. If you want any truthy value to match, then you can change from if (result === true) to if (result).

  • Related