使用Promise.all获得基于名称的结果的最佳方法

Ant*_*eth 16 javascript es6-promise

默认情况下,Promise.All([])函数返回一个基于数字的索引数组,该数组包含每个promise的结果.

var promises = [];
promises.push(myFuncAsync1()); //returns 1
promises.push(myFuncAsync1()); //returns 2
Promise.all(promises).then((results)=>{
    //results = [0,1]
}
Run Code Online (Sandbox Code Playgroud)

使用Promise.all()返回命名结果索引的最佳方法是什么?

我尝试使用Map,但它以这种方式返回数组中的结果: [key1, value1, key2, value2]

更新:

我的问题似乎不清楚,这就是为什么我不喜欢基于有序的索引:

  1. 维护很糟糕:如果在代码中添加一个promise,则可能需要重写整个结果函数,因为索引可能会有变化.
  2. 读起来很糟糕 :( results[42]可以通过下面的jib答案修复)
  3. 在动态上下文中不可用:
var promises = [];
if(...)
    promises.push(...);
else{
    [...].forEach(... => { 
        if(...)
            promises.push(...);
        else
            [...].forEach(... => {
                promises.push(...);
            });
    });
}
Promise.all(promises).then((resultsArr)=>{
    /*Here i am basically fucked without clear named results 
        that dont rely on promises' ordering in the array */
});
Run Code Online (Sandbox Code Playgroud)

jib*_*jib 54

ES6支持解构,所以如果你只想命名结果,你可以写:

var myFuncAsync1 = () => Promise.resolve(1);
var myFuncAsync2 = () => Promise.resolve(2);

Promise.all([myFuncAsync1(), myFuncAsync2()])
  .then(([result1, result2]) => console.log(result1 +" and "+ result2)) //1 and 2
  .catch(e => console.error(e));
Run Code Online (Sandbox Code Playgroud)

适用于Firefox和Chrome.

  • 我忘记了解构.这是做到这一点的好方法,值得接受. (7认同)
  • 无论您使用索引还是解构,当您在“Promise.all()”中有数十个条目时,无论哪种方式都没有帮助。 (2认同)
  • @ArturKlesun 这似乎是问题的问题,而不是答案的问题。我认为这里不言而喻,如果您想要基于名称的结果,则必须以某种方式提供这些名称,这对于数十人来说可能本质上是困难的,但仍然应该工作相同。`Promise.all` 适用于数组,不适用于对象。当然,聪明的人可以编写一个包装器来改变这一点...... (2认同)

spe*_*der 11

这是什么事吗?

var promises = [];
promises.push(myFuncAsync1().then(r => {name : "func1", result : r}));
promises.push(myFuncAsync1().then(r => {name : "func2", result : r}));
Promise.all(promises).then(results => {
    var lookup = results.reduce((prev, curr) => {
        prev[curr.name] = curr.result;
        return prev;
    }, {});
    var firstResult = lookup["func1"];
    var secondResult = lookup["func2"];
}
Run Code Online (Sandbox Code Playgroud)


Art*_*sun 7

如果您不想修改结果对象的格式,这里有一个辅助函数,它允许为每个条目分配一个名称以便稍后访问它。

const allNamed = (nameToPromise) => {
    const entries = Object.entries(nameToPromise);
    return Promise.all(entries.map(e => e[1]))
        .then(results => {
            const nameToResult = {};
            for (let i = 0; i < results.length; ++i) {
                const name = entries[i][0];
                nameToResult[name] = results[i];
            }
            return nameToResult;
        });
};
Run Code Online (Sandbox Code Playgroud)

用法:

var lookup = await allNamed({
    rootStatus: fetch('https://stackoverflow.com/').then(rs => rs.status),
    badRouteStatus: fetch('https://stackoverflow.com/badRoute').then(rs => rs.status),
});

var firstResult = lookup.rootStatus; // = 200
var secondResult = lookup.badRouteStatus; // = 404
Run Code Online (Sandbox Code Playgroud)

如果您使用打字稿,您甚至可以使用keyof构造指定输入键和结果之间的关系:

type ThenArg<T> = T extends PromiseLike<infer U> ? U : T;

export const allNamed = <
    T extends Record<string, Promise<any>>,
    TResolved extends {[P in keyof T]: ThenArg<T[P]>}
>(nameToPromise: T): Promise<TResolved> => {
    const entries = Object.entries(nameToPromise);
    return Promise.all(entries.map(e => e[1]))
        .then(results => {
            const nameToResult: TResolved = <any>{};
            for (let i = 0; i < results.length; ++i) {
                const name: keyof T = entries[i][0];
                nameToResult[name] = results[i];
            }
            return nameToResult;
        });
};
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述