我正在node.js(V8.1.3)中创建一个脚本,该脚本查看来自多个API的类似JSON数据并比较这些值。更确切地说,我正在研究不同股票的不同市场价格(实际上是加密货币)。
目前,我正在使用promise.all等待各个API的所有响应。
let fetchedJSON =
await Promise.all([getJSON(settings1), getJSON(settings2), getJSON(settings3) ... ]);
但是,即使只有一个承诺拒绝并出现错误,Promise.all也会抛出错误。在bluebird docos中有一个名为Promise.some的函数,这几乎就是我想要的。据我所知,它需要一系列承诺并解决两个最快的解决方案,否则(如果少于2个promises解决)会抛出错误。
问题在于,首先,我不希望最快的两个承诺被解决为它返回的,我希望任何成功的承诺被退回,只要有这似乎是Promise.any所做的,除非最小数为1.(我要求最低数量为2)
其次,我不知道我将等待多少Promise(换句话说,我不知道有多少API会从我那里请求数据)。它可能只有2或可能是30.这取决于用户输入。
目前写这篇文章在我看来,可能只有一种方法可以获得一个计数为2的promise.any,这将是最简单的解决方案。这可能吗?
是的,不确定标题是否真的总结了这个问题。请建议编辑标题:) 编辑:我编写脚本的另一种方法是,前两个加载的API开始计算并推送到浏览器,然后是后续加载和计算的每个JSON。这样我就不会等待所有Promise在我开始计算数据并将结果传递到前端之前完成。这个功能是否适用于其他情况呢?我的意思是这样的:
并行请求JSON ......
| ----- ------ JSON1 |
| --- JSON-失败--- | >捕获错误>做错事。不会影响下一个结果。
| ------- ------- JSON2 | >至少满足2个结果>计算JSON>浏览器。
| ------- JSON3 --------- | >计算JSON>浏览器。
答案 0 :(得分:5)
then
所有承诺如此失败,将其传递给Promise.all
,并在最终.then
中过滤成功结果。
这样的事情:
function some( promises, count = 1 ){
const wrapped = promises.map( promise => promise.then(value => ({ success: true, value }), () => ({ success: false })) );
return Promise.all( wrapped ).then(function(results){
const successful = results.filter(result => result.success);
if( successful.length < count )
throw new Error("Only " + successful.length + " resolved.")
return successful.map(result => result.value);
});
}
答案 1 :(得分:2)
考虑到您要求实施反模式,这可能有些笨拙,但您可以强迫每个承诺解决:
async function fetchAllJSON(settingsArray) {
let fetchedJSON = await Promise.all(
settingsArray.map((settings) => {
// force rejected ajax to always resolve
return getJSON(settings).then((data) => {
// initial processing
return { success: true, data }
}).catch((error) => {
// error handling
return { success, false, error }
})
})
).then((unfilteredArray) => {
// only keep successful promises
return dataArray.filter(({ success }) => success)
})
// do the rest of your processing here
// with fetchedJSON containing array of data
}
答案 2 :(得分:1)
您可以使用Promise.allSettled([])。所不同的是,在所有promise都成立后,无论成功还是失败,allSettled都将返回对象数组。然后找到成功的人,无论您需要什么。
let resArr = await Promise.allSettled(userNamesArr.map(user=>this.authenticateUserPassword(user,password)));
return resArr.find(e=>e.status!="rejected");
或返回resArr.find(e => e.status ==“ fulfilled”)。
答案 3 :(得分:0)
其他答案的缺点是必须等待所有的诺言得以解决,而理想情况下,.some
将在任何(N)个诺言通过谓词后立即返回。
let anyNPromises = (promises, predicate = a => a, n = 1) => new Promise(async resolve => {
promises.forEach(async p => predicate(await p) && !--n && resolve(true));
await Promise.all(promises);
resolve(false);
});
let atLeast2NumbersGreaterThan5 = promises => anyNPromises(promises, a => a > 5, 2);
atLeast2NumbersGreaterThan5([
Promise.resolve(5),
Promise.resolve(3),
Promise.resolve(10),
Promise.resolve(11)]
).then(a => console.log('5, 3, 10, 11', a)); // true
atLeast2NumbersGreaterThan5([
Promise.resolve(5),
Promise.resolve(3),
Promise.resolve(10),
Promise.resolve(-43)]
).then(a => console.log('5, 3, 10, -43', a)); // false
atLeast2NumbersGreaterThan5([
Promise.resolve(5),
Promise.resolve(3),
new Promise(() => 'never resolved'),
Promise.resolve(10),
Promise.resolve(11)]
).then(a => console.log('5, 3, unresolved, 10, 11', a)); // true