简体   繁体   中英

Looking for Bluebird promise function "any" as series

I have a requirement to run Promise.any in series.

As it's not available (Am I right?) I wrote a function to execute promises in series (with help of Pomise.mapSeries ) and resolves at first test satisfied.

The approach is:

  • on resolution of test function check if the result satisfied the criteria or not.
  • if criteria is not matched, mapSeries anyway will continue.
  • If criteria is matched then reject with custom error. It will break the mapSeries.
  • then in catch of mapSeries function check if error is custom error, if there is custom error then resolve with required result, else reject the error further down.

Here is the code:

const Promise = require('bluebird')

let delay = 1000
const BIG = 10

function isBig (n) {
  return Promise.delay(delay).then(() => {
    console.log('[test] n: ', n)
    if (n < 0) return Promise.reject(new Error('Negative number'))
    else if (n > BIG) return Promise.resolve(n)
    else return Promise.resolve(false)
  })
  delay -= 100  // just to check array items are executing in series
}

function anySeries (arr, test) {
  return Promise.mapSeries(arr, n => {
    return isBig(n)
    .then(res => {
      if (res) {
        let err = new Error('Stop As Found')
        err.result = n
        return Promise.reject(err)
      } else {
        return res
      }
    })
  })
  .then(res => {
    console.log('[AS] each output: ' + JSON.stringify(res))
    return null
  }).catch(err => {
    console.log('[AS] Let me check error')
    if (/^Stop As Found$/.test(err.message)) {
      console.log('[AS] Found the desired')
      console.log('[AS] Final result: ', err.result)
      return Promise.resolve(err.result)
    } else {
      console.error('[AS] Internal error')
      console.error('[AS] Returing error: ', err.message)
      return Promise.reject(err)
    }
  })
}

let arr = [ 1, 11, 5, -1, 13, 15]
// find bigger than 10
console.log('---Test 1 (will find)---')
anySeries(arr, isBig)
.then(res => {
  console.log('Arr: %s, Big one: %s', arr, res)
  arr = [ 1, 3, 5]
  console.log('\n---Test 2 (will not find)---')
  return anySeries(arr, isBig)
})
.then(res => {
  console.log('Arr: %s, Big one: %s', arr, res)
  arr = [ 1, 2, -1, 13, 15, 2]
  console.log('\n---Test 3 (wiil result in error)---')
  return anySeries(arr, isBig)
})
.catch(console.error)

If there is better approach I would like to know, preferably with Promise.

A simpler way to do this is to simply loop over your input values and await the promise.

  • You have an array of values, arr
  • You want to transform these into a promise (one at a time), isBig
  • If the value passes some check if (res) , don't continue processing the rest of the array
async function series(values, map, check) {
  for (let i = 0; i < values.length; i++) {
    const res = await map(values[i], i, values);
    if (check(res, i, values)) {
      return res;
    }
  }
  // This might be desirable or it might not. Up to you.
  throw new Error('No result');
}

series(arr, isBig, (res) => !!res)
  .then((result) => {
    // A value was resolved to.
    console.log('[AS] Found the desired');
    console.log('[AS] Final result: ', result);
  })
  .catch((err) => {
    console.error('[AS] Internal error');
    console.error('[AS] Returning error: ', err.message);
  });

If you want to make processing the array 'fault tolerant' by ignoring any errors you can add a try {... } catch {} inside the for loop. If you want to have a default value that series resolves to, add a return...; at the end of the async function rather than throw .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM