1

I need to run an asynchronous code inside an array.some() which in itself is inside and array.every(). So basically I wanted the callbacks to be async so I can use await inside them.

But neither Array.prototype.some() nor Array.prototype.every() accept asynchronous callbacks, which would require them to return a Promise instead.

Madacol
  • 3,611
  • 34
  • 33
  • 1
    https://stackoverflow.com/questions/56553286/how-to-use-array-prototype-some-with-an-async-function/56553349#56553349 has a `some` with a few more optimizations, but this is probably a better question for it since that question was better solved in a different way. – Ry- Dec 06 '19 at 22:01

1 Answers1

3

This are the asynchronous versions of some() and every() that I came up with

someAsync()

Array.prototype.someAsync = function (callbackfn) {
    return new Promise(async (resolve,reject) => {
        await Promise.all(this.map(async item => {
            if (await callbackfn(item))   resolve(true)
        })).catch(reject)
        resolve(false)
    })
}

// Examples
['',0,undefined,false].someAsync(async e=>e).then(e=>console.log(e)) // false
['',0,undefined,false,true].someAsync(async e=>e).then(e=>console.log(e)) // true

everyAsync()

Array.prototype.everyAsync = function (callbackfn) {
    return new Promise(async (resolve,reject) => {
        await Promise.all(this.map(async item => {
            if (! await callbackfn(item))   resolve(false)
        })).catch(reject)
        resolve(true)
    })
}

// Examples
[[],{},1,true].everyAsync(async e=>e).then(e=>console.log(e)) // true
[[],{},1,true,false].everyAsync(async e=>e).then(e=>console.log(e)) // false

Disadvantages

  • They only accept the callback and with one argument only
  • Even though someAsync() resolves true as soon as a truthy value is resolved and everyAsync() resolves false as soon as a falsy value is resolved, the callback is still executed till the end for every element, even if the method's promise has already resolved. I think this has no straightforward solution as long as promises are not cancellable
Madacol
  • 3,611
  • 34
  • 33
  • 1
    Promise executors shouldn’t be `async` when the they can throw, and these ones can – any rejections in the array will end up making an unhandled rejection. `(resolve, reject) => Promise.all(…).then(() => { resolve(false or true) }).catch(reject)` instead, maybe? – Ry- Dec 06 '19 at 22:06
  • 1
    The disadvantage only exists because the elements are not processed sequentially. Processing the elements sequentially has it's own disadvantages, but it is more in line with the synchronous version of these methods. – Jake Holzinger Dec 06 '19 at 22:19
  • 1
    @Ry- why not? You just have to remember to use `try/catch` and call `reject` in the catch block. Similar to your proposal using `then/catch`. – Jake Holzinger Dec 06 '19 at 22:24
  • Made this a wiki, so you can all improve it – Madacol Dec 06 '19 at 22:28
  • @JakeHolzinger: I said (well, typoed with an extra “the”) “when they can throw”. If you use `try` correctly, they can’t throw. – Ry- Dec 07 '19 at 19:05