Promise.all 可以把
[Promise a, Promise b]
变成 Promise [a, b]
,超级有用,但是还有没有办法把 {a: Promise a, b: Promise b}
变成 Promise {a, b}
。
用例是:
我有一个函数可以从网站加载一些文件,并在失败时返回错误消息。 这意味着,它的签名是
information -> {values: values, messages: messages}
。
但是整个检查是异步的,所以结果是
information -> {values: Promise values, messages: promise messages}
这是我的超级简单的解决方案:
export const objectZip = (keys, values) =>
keys.reduce(
(others, key, index) => ({
...others,
[key]: values[index],
}),
{}
);
export const objectPromise = async obj =>
objectZip(Object.keys(obj), await Promise.all(Object.values(obj)));
您可以手动完成:
function objectPromise(obj) {
return Promise.all(Object.keys(obj).map(function (key) {
return Promise.resolve(obj[key]).then(function (val) {
return {key: key, val: val};
});
})).then(function (items) {
var result = {};
items.forEach(function (item) {
result[item.key] = item.val;
});
return result;
});
}
用法
var testObj = {
a: Promise.resolve("a"),
b: Promise.resolve("b"),
c: "c"
};
objectPromise(testObj).then(function (obj) {
console.log(obj);
});
//> { a: 'a', b: 'b', c: 'c' }
ES6 语法中的相同内容,如果您愿意的话:
var objectPromise = obj => Promise.all(
Object
.keys(obj)
.map(key => Promise.resolve(obj[key]).then(val => ({key: key, val: val})))
).then(items => {
let result = {};
items.forEach(item => result[item.key] = item.val);
return result;
});
据我所知不,但你可以准备一个返回对象,你就会知道它何时准备好
function multipleAsyncJobs(){
ret = {};
var a = new Promise(function(resolve, reject){
ret.a = someVal; // set
resolve();
})
var b = new Promise(function(resolve, reject){
ret.b = someVal; // set
resolve();
})
return new Promise(function (resolve, reject) {
Promise.all([a,b]).then(function(){
resolve(ret)
})
})
}
你可以像这样使用这个函数,这样就可以像往常一样返回一个承诺
multipleAsyncJobs().then(ret=>{
console.log(ret.a)
})
我敢于提出另一种选择(带有一些进一步的提示):
export async function promiseAllOfObject(obj) {
const values = await Promise.all(Object.values(obj));
return Object.keys(obj).reduce(
(res, key, index) => (res[key] = values[index], res),
{}
);
}
分别将
Promise.all
替换为 Promise.allSettled
即可获得 promiseAllOfObjectSettled()
功能。
而且,作为一个小福利,这里是打字稿版本(替换为
Promise.allSettled
与上面的效果相同):
export async function promiseAllOfObject<
T extends Record<string, unknown> = Record<string, unknown>,
>(obj: {
[P in keyof T]: Promise<T[P]>;
}): Promise<T> {
const values = await Promise.all(Object.values(obj));
return Object.keys(obj).reduce((res, key, index) => {
res[key] = values[index];
return res;
}, {} as Record<string, unknown>) as T;
}
使用 Object.fromEntries(iterable),从 ES10 / ES2019 开始,类似于 这篇文章,但添加了类型:
async function promiseAllOfObject<T extends Object>(obj: T): Promise<{
[key in keyof T]: Awaited<T[key]>
}> {
const entries = Object.entries(obj).map(async ([key, value]) => [key, await value])
return Object.fromEntries(await Promise.all(entries))
}