异步函数返回promise数组,而不是实际的值数组

时间:2019-09-12 16:14:26

标签: javascript promise async-await

我有一个函数,该函数将接受整数数组,然后它将调用另一个函数,该函数将接受一个整数并进行一些检查并返回一个承诺以解决该问题。

我知道getDataById函数并不是在做异步工作,但是请记住,这只是示例。

这是我的代码:

function getDataById(id) {
    return new Promise((resolve, reject) => {
        if (id > 0) resolve(id * 10);
        if (id <= 0) reject("wrong input");
    })
}

async function callService(idList) {
    return await idList.map((id) => getDataById(id));
}

let teamIDList = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, -1, -2, -3, -4];


callService(teamIDList).then(res => {
    console.log(res);
});

我希望它会返回一个包含新数字和一些字符串的数组。 但是它返回了一系列承诺。

1 个答案:

答案 0 :(得分:2)

await在为它提供数组时并没有做任何特别的事情,它只是将数组包装在已解决的承诺中。

要等待兑现承诺,请使用Promise.all

async function callService(idList) {
    return await Promise.all(idList.map((id) => getDataById(id)));
}

或者:

function callService(idList) {
    return Promise.all(idList.map((id) => getDataById(id)));
}

(附带说明:不需要该箭头功能:

return await Promise.all(idList.map(getDataById));

请注意,两者都按以下顺序进行操作:

  • 为每个getDataById呼叫id
  • 等待所有这些诺言兑现,或者其中一个失败
  • 如果所有条件都得到满足,则使用结果数组来解决callService的诺言(请记住,async函数总是返回诺言)

如果您想等待对getDataById的每次调用之前完成对下一次对getDataById的调用,则可以通过一个简单的循环来完成它:

// **IF** you wanted to wait for each `getDataById` call to finish
// before starting the next
async function callService(idList) {
    const result = [];
    for (const id of idList) {
        result.push(await getDataById(id));
    }
    return result;
}

(如果需要,您也可以将其拔成reduce,但它不会给您带来任何好处。)

但是我想您想要上面的第一个代码块,以并行方式启动所有调用并等待它们完成。


您在评论中说,您的老板不希望您使用Promise.all,因为如果有任何承诺被拒绝,它就会被拒绝。是的,的确如此。如果您不希望这样做,则可以改用allSettled。这是一个Stage 4 proposal(例如,正在JavaScript引擎中积极实现),可以很容易地对其进行填充。

async function callService(idList) {
    return await Promise.allSettled(idList.map(getDataById));
}

或者:

function callService(idList) {
    return Promise.allSettled(idList.map(getDataById));
}

结果是一个对象数组,其中兑现了承诺:

{
    status: "fulfilled",
    value: (the value)
}

和被拒绝的人看起来像这样:

{
    status: "fulfilled",
    reason: (the rejection reason)
}

很显然,如果您要转换该数组,则可以轻松进行。例如,如果您要为无法检索的返回null

async function callService(idList) {
    return (await Promise.allSettled(idList.map(getDataById)))
           .map(entry => entry.status === "fulfilled" ? entry.value : null);
}

或者如果您想将它们过滤掉:

async function callService(idList) {
    return (await Promise.allSettled(idList.map(getDataById)))
           .map(entry => entry.status === "fulfilled" ? entry.value : null)
           .filter(entry => entry !== null);
}

如果您想同时过滤和映射,我们可能会稍微滥用flatMap ::-)

async function callService(idList) {
    return (await Promise.allSettled(idList.map(getDataById)))
           .flatMap(entry => entry.status === "fulfilled" ? entry.value : []);
}