我正在使用
Promise.all
进行一些批量 IO,但最终我通过一次创建太多 IO 承诺而达到了打开文件的限制。因此,我制作了一个实用程序,它将最多以 50 个批次运行这些承诺。
一种解决方案是将任务分成 50 批,然后对每批执行
Promise.all
。但更明智的解决方案是使用 Promise.any
来循环承诺。问题是,Promise.any
只返回结果,而不返回哪个promise。
如何找出已解决的问题,以便我可以在批次中用新的未解决的问题替换它?
没有本地方法可以找到已完成的
Promise
。
但我想到了一个解决方法。基本上,我为每个
Promise
分配了一个 id,然后解构 Promise
的返回值并注销 id 和结果
const Promise4 = fetch('https://pokeapi.co/api/v2/ability/?limit=1&offset=20').then(response => response.json()).then(result => ({
id: 4,
result
}));
const Promise1 = fetch('https://pokeapi.co/api/v2/ability/?limit=1&offset=12').then(response => response.json()).then(result => ({
id: 1,
result
}));
const Promise2 = fetch('https://pokeapi.co/api/v2/ability/?limit=1&offset=5').then(response => response.json()).then(result => ({
id: 2,
result
}));
const Promise3 = fetch('https://pokeapi.co/api/v2/ability/?limit=1&offset=23').then(response => response.json()).then(result => ({
id: 3,
result
}));
Promise.any([Promise1, Promise2, Promise3, Promise4]).then(({
id,
result
}) => console.log(`Promise${id} returned`, result.results[0].name));
与a.mola的答案类似,但保持承诺索引跟踪更接近
Promise.any
调用,我们可以在输入数组上map
添加标签并解构以检索它:
const promises = [
new Promise(resolve => setTimeout(() => resolve("p0value"), 1000)),
new Promise(resolve => setTimeout(() => resolve("p1value"), 500))
];
const promiseAnyIndexed = pp => Promise.any(pp.map((p,i)=>p.then(res=>[res,i])));
const [res, i] = await promiseAnyIndexed(promises);
console.log(res,i); // p1value 1
在这里留下我的 2 美分:我喜欢做的是覆盖返回值以包含承诺本身,以便它可以轻松匹配:
export function refPromise(promise) {
// This function ensures a promise resolves/rejects with a reference to itself, so usage in methods
// like 'Promise.race' or 'Promise.any' allows us to know which promise returned.
const refPromise = promise
.then((value) => {
return { promise: refPromise, value };
})
.catch((reason) => {
throw { promise: refPromise, reason };
});
return refPromise;
}
这是一个例子:
const p1 = refPromise(new Promise((r) => setTimeout(() => r("a"), 1000)));
const p2 = refPromise(new Promise((r) => setTimeout(() => r("b"), 500)));
try {
const { promise, value } = await Promise.any([p1, p2]);
if (promise === p1) {
console.log("p1 resolved!", value);
} else if (promise === p2) {
console.log("p2 resolved!", value);
}
} catch (e) {
const { promise, reason } = e;
// Can treat 'promise' the same way as above
}