给定一个函数,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 ... */ }); }); });
我觉得也许这种模式的优雅解决方案是我所缺少的.这个行为与Array.some()非常相似,但是我试图摆弄它是空洞的.
编辑:我从数字数据切换到字符串,以强调解决方案不需要依赖于数字数据.
编辑#2:为了进一步澄清,fn可以是任何接受输入并返回promise的函数.上面的fn实现只是为了给出一个完整的例子.实际上,fn实际上可能类似于API请求,数据库查询等.
解决方法
您可以使用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(等待)或只返回一个值(返回)
>您的数据可能是无限可迭代序列(生成器)
>在我看来,它也易于阅读和理解意图.
如果序列失败,这是输出:
trying apple trying orange trying banana trying pineapple trying pear trying plum Error: not found
异步的支持在es2017中是原生的,但可以用babel或typescript转换为es3 / es5