我有几个异步函数,如果值尚未提供,则获取和存储该值。
if (!output.valueA) {
output.valueA = await getValueA();
}
if (!output.valueB) {
output.valueB = await getValueB();
}
我知道可以使用 Promise.all() 异步等待这两个调用,但是如果不知道是否需要其中一个或两个调用,那么最好的方法是什么,并将结果存储在正确的变量中?
我有几个异步函数,如果值尚未提供,则获取和存储该值。
if (!output.valueA) {
output.valueA = await getValueA();
}
if (!output.valueB) {
output.valueB = await getValueB();
}
我知道可以使用 Promise.all() 异步等待这两个调用,但是如果不知道是否需要其中一个或两个调用,那么最好的方法是什么,并将结果存储在正确的变量中?
您可以创建包含所有承诺的数组,根据存在值进行过滤,然后使用Promise.all
。您还需要一个属性键到异步函数的一对一映射,用于获取该键的值:
const fns = {
"valueA": getValueA,
"valueB": getValueB,
};
const keys = Object.keys(fns);
// all keys
const missing = keys.filter((key) => !output[key]);
// keys with missing values
const promises = missing.map((key) => fns[key]());
// an array of promises
const results = await Promise.all(promises);
// promise results, obviously
for (const [ index, key ] of missing.entries()) { // using Array.prototype.entries
output[key] = results[index];
}
在不大幅更改您的示例的情况下,您可以使用then
来设置一个回调来在解析时设置属性。将结果的Promise存储在数组中,以便您知道什么时候所有的Promise都已完成。
const promises = [];
if (!output.valueA) {
promises.push(getValueA().then(value => output.valueA = value));
}
if (!output.valueB) {
promises.push(getValueB().then(value => output.valueB = value));
}
await Promise.all(promises);
代码如下:
const asyncGetters = [["valueA", getValueA], ["valueB", getValueB]];
await Promise.all(
asyncGetters
.filter(([prop]) => !output[prop])
.map(async ([prop, asyncGetter]) => output[prop] = await asyncGetter())
);
在这里,filter
的作用类似于你的 if
语句,只选择具有假值的元素。map
确保收集异步 map
回调的承诺,因此您可以使用 await Promise.all()
等待它们全部完成。
promises.push((async () => output.valueA = await getValueA())())
,但我个人认为异步 IIFE 作为函数参数有点晦涩难懂。 - 3limin4t0rconst output = {
valueA : null,
valueB: null
};
async function getValueA() {
await new Promise(r => setTimeout(r, 3000));
output.valueA = 2;
return output.valueA;
}
async function getValueB() {
await new Promise(r => setTimeout(r, 3000));
output.valueB = 5;
return output.valueB;
}
async function getAllValues() {
const promises = [output.valueA || getValueA(), output.valueB || getValueB()];
await Promise.all(promises);
console.log(output.valueA);
console.log(output.valueB);
}
getAllValues();
Promise.all
传递一个包含实际值的数组,它会立即解析。不需要确保它们都是promise。尝试运行上面的代码,但将output.valueA和valueB更改为数字 - 它将立即解析。
[编辑]
阅读OP的评论并出于说明目的进行了以下操作:
const output = {
valueA : null,
valueB: null
};
async function getValueA() {
await new Promise(r => setTimeout(r, 3000));
return 2;
}
async function getValueB() {
await new Promise(r => setTimeout(r, 3000));
return 5;
}
async function getAllValues() {
const promises = [output.valueA || getValueA(), output.valueB || getValueB()];
const [a, b] = await Promise.all(promises);
output.valueA = a;
output.valueB = b;
console.log(output.valueA);
console.log(output.valueB);
}
getAllValues();
Promise.all
的结果getValueA
和 getValueB
(以及所有后续类似的获取器)进行重新定义,以适应每个新值的 output
。 - Parzh from UkrainegetValueA
和getValueB
存在于一个单独的模块中,所以最好根据函数的结果设置输出值,而不是在函数内部设置。 - DBPaul
output
来自哪里?或者对于任务来说它是无关紧要的吗? - Parzh from Ukraineoutput
的结构,还是它每次都有新属性? - Parzh from Ukraine