异步/等待内部 for...of 与 map

问题描述 投票:0回答:3

我试图弄清楚为什么 Promise 在

for...of
map()
中的工作方式似乎有所不同。

data
{app: MY_APP, link: MY_LINK}
形式的对象数组。我正在尝试将其转换为
{app: MY_APP, status: true OR false}}
的形式。函数
checkLink()
是异步的,因为它使用
node-fetch
并基本上返回给定链接是否为 200。使用
for...of
,我得到了所需的对象:

let objToSend = [];
for (obj of data) {
  objToSend.push({ app: obj.app, status: await checkLink(obj.link) });
}

// returns [{app: MY_APP, status: true}, ...]

但是使用

map
,如下所示,我得到了一组待处理的承诺。任何帮助将不胜感激:

let objToSend = data.map(async obj => {
  return {
    app: obj.app,
    status: await checkLink(obj.link)
  };
});

// returns [ Promise { <pending> }, ...]

我还尝试在

Promise.all(objToSend)
代码之后执行
map
,但它反而返回
Promise { <pending> }

javascript for-loop promise
3个回答
4
投票

我将把解释留给其他答案,但只是想指出,也存在性能差异。

您的第一个解决方案会在每次迭代中等待承诺的解决,只有在前一个解决方案已解决时才调用

checkLink
。这是一个顺序解决方案。

check link1 => wait => check link2 => wait => check link3 => wait

第二种解决方案迭代每个元素并发出请求,而不等待 Promise 解决;因此,返回了一组承诺。如果您等待所有承诺都得到解决,您会发现此解决方案要快得多,因为请求是并行发送的。

check link1 => check link2 => check link3 => wait for all

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));

async function checkLink(link) {
  await sleep(Math.random() * 1000 + 500); // sleep between 500 and 1500 ms
  console.log(link);
  return `status #${link}`;
}

(async function () {
  const data = new Array(5).fill().map((_, index) => ({ app: "app", link: index }));
  let objToSend;
  
  console.log("solution #1");
  objToSend = [];
  for (let obj of data) {
    objToSend.push({ app: obj.app, status: await checkLink(obj.link) });
  }
  console.log(objToSend);

  console.log("==============================================");
  
  console.log("solution #2");
  objToSend = await Promise.all(data.map(async obj => {
    return {
      app: obj.app,
      status: await checkLink(obj.link)
    };
  }));
  console.log(objToSend);
})();

在代码片段中,第一个解决方案需要 2500 到 7500 毫秒之间的时间,而第二个解决方案需要 500 到 1500 毫秒之间的时间(取决于解析的最慢值)。

    


2
投票
异步函数

总是返回Promises。在您的映射函数中,当回调返回 Promise 时,就会创建一个 Promise 数组。 要将其转换为您的格式,请与

500/1500 * 5 = 2500/7500

:
一起使用 Promise.all()



1
投票
(async()=>{ let objToSend = await Promise.all(data.map(async obj => { return { app: obj.app, status: await checkLink(obj.link) }; })); console.log(objToSend) //[{app: MY_APP, status: true}, ...] })()

始终会停止其所在的

await
的执行,在这两种情况下它的工作方式没有不同。然而,在后面的示例中,您确实调用了一些
async function
,并且这些调用将评估为承诺,而在第一个示例中,所有这些
async function
都位于相同的
await
中。

我也尝试在地图代码之后执行
async function

,但它反而返回

Promise.all(objToSend)


是的,
Promise { <pending> }

,您会得到一系列结果。

    

© www.soinside.com 2019 - 2024. All rights reserved.