【问题标题】:Async/await in foreach not waiting [duplicate]foreach中的异步/等待不等待[重复]
【发布时间】:2019-06-29 03:44:07
【问题描述】:

我正在尝试在使用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 作为空数组返回。我该如何解决这个问题?

【问题讨论】:

    标签: javascript async-await


    【解决方案1】:

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

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

    实际上,真正的实现是the following,但底线是我们不是在等待回调完成,所以使用返回promise的函数不会等待承诺每次都解决。

    您的代码不是complete and verifiable,所以我不能确定以下代码是否有效,但它可能应该如您所愿:

    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;
    }
    

    您可能还想查看this CodeBurst article on foreach + async/await

    【讨论】:

    • 在我的getEvents() 函数中,我需要说await addExtrasToDocsForUser(docs, currentUserId, events) 还是可以删除那里的await
    • 保留await。如果你删除它,它只会启动承诺,而不是等待承诺首先解决。
    【解决方案2】:

    使用Promise.allmap 获取所有内部承诺并返回一个等待它们的单一承诺:

    const addExtrasToDocsForUser = async (docs, currentUserId, events) => {
        return Promise.all(docs.map(async (eventDoc) => {
            const event = await addExtrasToDocForUser(eventDoc, currentUserId)
            events.push(event)
        }));
    }
    

    【讨论】:

      【解决方案3】:

      为什么要结合同步和异步函数?
      你调用await addExtrasToDocsForUser(docs, currentUserId, events),但你的函数addExtrasToDocsForUser不是async

      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()

      【讨论】:

        猜你喜欢
        • 2017-01-11
        • 1970-01-01
        • 2021-08-23
        • 2019-01-15
        • 2016-07-07
        • 2016-03-25
        • 2017-10-09
        相关资源
        最近更新 更多