在foreach循环中使用async/await无法等待

19

我正在尝试在使用forEach循环的函数中使用asyncawait。令人烦恼的是,我无法使其正常工作。应该发生的是它接受一个事件docs数组,遍历它们,添加一些额外的数据,然后将它们推送到events数组中。这个events数组然后从原始函数返回。这是我的代码:

async function getEvents() {
  ...
  var events = []
  await addExtrasToDocsForUser(docs, currentUserId, events)
  return events

}


var addExtrasToDocsForUser = (docs, currentUserId, events) => {
    return docs.forEach(async (eventDoc) => {
        const event = await addExtrasToDocForUser(eventDoc, currentUserId)
        events.push(event)
    })
}

实际发生的是getEvents()函数在forEach循环完成之前将events返回为空数组。我该如何修复?

3个回答

11

基本上,这就是forEach内部发生的事情:

Array.prototype.forEach = function (callback) {
  for (let index = 0; index < this.length; index++) {
    callback(this[index], index, this);
  }
};

实际上,真正的实现是这个,但关键是我们不会等待回调函数完成,因此使用返回 Promise 的函数并不会在每次 Promise 解决时等待。

你的代码不够完整可验证,所以我不能确定下面的代码能否按照你的期望工作,但它很可能会:

const addExtrasToDocsForUser = async (docs, currentUserId, events) => {
  for (let i=0; i<docs.length; i++) {
    const event = await addExtrasToDocForUser(docs[i], currentUserId);
    events.push(event);
  }
  return;
}

你可能还想查看这篇 CodeBurst 文章,介绍了 foreach + async/await 的用法。


在我的 getEvents() 函数中,我需要说 await addExtrasToDocsForUser(docs, currentUserId, events) 吗?还是可以将其中的 await 删除掉? - Tometoyou
保留 await。如果您将其删除,它只会启动 Promise,而不等待 Promise 首先解决。 - Nino Filiu

9
使用Promise.allmap获取所有内部promise并返回一个单一的promise来等待它们全部完成:
const addExtrasToDocsForUser = async (docs, currentUserId, events) => {
    return Promise.all(docs.map(async (eventDoc) => {
        const event = await addExtrasToDocForUser(eventDoc, currentUserId)
        events.push(event)
    }));
}

2
为什么要同时使用同步和异步函数? 你调用了await addExtrasToDocsForUser(docs, currentUserId, events),但是你的函数addExtrasToDocsForUser不是异步的。最初的回答。
var addExtrasToDocsForUser = async (docs, currentUserId, events) => {
  return await docs.forEach(async (eventDoc) => {
    const event = await addExtrasToDocForUser(eventDoc, currentUserId)
    events.push(event)
  })
}

你想做这样的事情:

你需要做出这样的回答:

var someOperation = async (op0, op1) => {
 return op0+':'+op1
}

var fnWithForeach = async (docs, number, outputs)=>{
  return await docs.forEach(async (doc)=>{
 const output = await someOperation(doc, number)
 outputs.push(output) 
  })
}

async function getOutputs() {
  // ...
  var docs = ['A', 'B', 'C']
  var number = 10
  // ...
  var outputs = []
  await fnWithForeach(docs, number, outputs)
  return outputs
}

async function main() {
  // ...
  var outputs = await getOutputs()
  console.log(outputs)
  // ...
}

main()


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接