How to link promises to failure

For a function fnthat returns a promise and an array of arbitrary data length (for example data = ['apple', 'orange', 'banana', ...]), how do you bind function calls for each element of the array sequentially, so if it fn(data[i])resolves, the whole chain ends and stops the call fn, but if it is fn(data[i])rejected, the next call fn(data[i + 1])is made?

Here is a sample code:

// 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 that maybe there is an elegant solution to this model that I am missing. The behavior is very similar to Array.some(), but I came empty trying to play with it.

EDIT: I switched from numeric data to string to emphasize that the solution should not rely on numeric data.

# 2: , fn , . fn , . fn - API, ..

+6
5

async/await :

async function search() {
  for (let item of data) {
    try {
      return await fn(item);
    } catch (err) { }
  }
  throw Error ("not found"); 
}

search().then(foundResult).catch(console.log);
  • fn Promise (), ()
  • data iterable ()
  • , .

, :

trying apple
trying orange
trying banana
trying pineapple
trying pear
trying plum
Error: not found

async es2017, es3/es5 babel typescript

+5

Array.reduce .

data.reduce((promise, item) => promise.then(
  (param) => {
    if (param) return Promise.resolve(param);
    return fn(item).catch(() => Promise.resolve());
  } 
), Promise.resolve())
.then(foundResult)

, . fn , undefined , fn.

+4

, :

function search(number) {
    if (number < data.length) {
        fn(data[number]).then(foundResult)
              .catch(() => search(number + 1));
    }
}

search(0);
+2

, catch.

function find_it(arr) {
   let [head, ...rest] = arr

   if (!head) return console.log("not found") // all rejects or no data

   fn(head)
   .then(r => foundResult(r) )
   .catch(r => find_it(rest))
}
find_it(data)

, , data, . , , promises - .

:

$node./test
apple

=

:

$node./test apple




+1

, , , ( , . ):

const fn = n => new Promise(() => {});
const seq = [];
const process = n => fn(n).then(foundResult);

seq.slice(1).reduce((operation, item) => {

    return operation
        .catch(() => process(item));

}, process(seq[0]));

Promise.race:

const fetchAll = ( urls = [] ) => Promise.race(urls.map(fn)).then(foundResult);

, , : , catch, , foundResult . , , foundResult, fn.

, , promises "" . , , , , rejectionValue fulfillmentValue.

, , .

0

All Articles