异步/等待内部...的地图

时间:2019-07-11 14:53:18

标签: javascript for-loop promise

我试图弄清楚为什么承诺在for...ofmap()内部似乎有所不同。

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,如下所示,我得到了一系列待处理的Promise。任何帮助将不胜感激:

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

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

我还尝试在Promise.all(objToSend)代码之后执行map,但是它返回了Promise { <pending> }

3 个答案:

答案 0 :(得分:1)

await总是停止执行其中的async function,在两种情况下它的工作方式都没有不同。但是,在后面的示例中,您确实调用了一些async function,而这些调用将评估为Promise,而在您的第一个示例中,所有这些await都在同一async function中。 / p>

  

我还尝试在地图代码之后执行Promise.all(objToSend),但它返回Promise { <pending> }

是的,await,您会得到一系列结果。

答案 1 :(得分:1)

Async functions始终为returns Promises。在您的map函数中,当回调函数返回promise时,将创建一个promise数组。

要将其转换为您的格式,请与Promise.all()一起使用:

(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}, ...]
})()

答案 2 :(得分:1)

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

您的第一个解决方案会在每次迭代中等待承诺的解决。仅在上一个已解决的情况下才呼叫checkLink。这是一个顺序解决方案。

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

第二种解决方案遍历每个元素并发出请求,而无需等待promise解决(因此,将返回一个promise数组)。如果您等待所有承诺都得到解决,您会发现此解决方案要快得多,因为请求是并行发送的。

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

const sleep = async 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 * 5 = 2500/7500。而第二种解决方案则需要500到1500毫秒(取决于要解决的最慢值)。