Given a function, fn, which returns a promise, and an arbitrary length array of data (e.g. data = ['apple', 'orange', 'banana', ...]) how do you chain function calls on each element of the array in sequence, such that if fn(data[i]) resolves, the whole chain completes and stops calling fn, but if fn(data[i]) rejects, the next call fn(data[i + 1]) executes?
Here is a code example:
// this could be any function which takes input and returns a promise
// one example might be fetch()
const fn = datum =>
new Promise((resolve, reject) => {
console.log(`trying ${datum}`);
if (Math.random() < 0.25) {
resolve(datum);
} else {
reject();
}
});
const foundResult = result => {
// result here should be the first value that resolved from fn(), and it
// should only be called until the first resolve()
console.log(`result = ${result}`);
};
// this data can be purely arbitrary length
const data = ['apple', 'orange', 'banana', 'pineapple', 'pear', 'plum'];
// this is the behavior I'd like to model, only for dynamic data
fn('apple').then(foundResult)
.catch(() => {
fn('orange').then(foundResult)
.catch(() => {
fn('banana').then(foundResult)
.catch(() => {
/* ... and so on, and so on ... */
});
});
});
I feel like maybe there's an elegant solution to this pattern that I'm missing. The behavior is very similar to Array.some(), but I've come up empty trying to fiddle with that.
EDIT: I switched from numeric data to string to stress that the solution needs to not be reliant on the data being numeric.
EDIT #2: Just to clarify further, fn could be any function that accepts input and returns a promise. The fn implementation above was just to give a complete example. In reality, fn could actually be something like an API request, a database query, etc.