如何在拒绝上链接承诺

FtD*_*Xw6 6 javascript promise

给定一个函数,fn它返回一个promise,以及一个任意长度的数据数组(例如data = ['apple', 'orange', 'banana', ...])如何按顺序将数组的每个元素上的函数调用链接起来,这样如果fn(data[i])解析,整个链完成并停止调用fn,但是如果fn(data[i])拒绝,下一个呼叫fn(data[i + 1])执行?

这是一个代码示例:

// 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 ... */
          });
      });
  });
Run Code Online (Sandbox Code Playgroud)

我觉得也许这种模式的优雅解决方案是我所缺少的.这种行为非常相似Array.some(),但是我试图摆弄那种空洞.

编辑:我从数字数据切换到字符串,以强调解决方案不需要依赖于数字数据.

编辑#2:进一步澄清,fn可以是任何接受输入并返回承诺的函数.fn上面的实现只是为了给出一个完整的例子.实际上,fn实际上可能是API请求,数据库查询等.

Mei*_*hes 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);
Run Code Online (Sandbox Code Playgroud)
  • fn 可以返回Promise(等待)或只返回一个值(返回)
  • data可能是一个无限的iterable序列(发电机)
  • 在我看来,它也易于阅读和理解意图.

如果序列失败,这是输出:

trying apple
trying orange
trying banana
trying pineapple
trying pear
trying plum
Error: not found
Run Code Online (Sandbox Code Playgroud)

对于异步的支持是在es2017天然的,但可transpiled到ES3/ES5与巴别打字稿