【问题标题】:Javascript - passing an asynchronous callback to Array.reduce()Javascript - 将异步回调传递给 Array.reduce()
【发布时间】:2020-08-07 01:53:50
【问题描述】:

我正在开发一个使用 Array.reduce 的函数,我需要在 reduce 函数中添加一个异步 API 调用。这需要我对传入reduce 的回调使用异步函数,因为我在函数内部使用await 来等待异步API 调用。

我在正确编写 reduce 时遇到了一些问题。以下是它目前的情况(工作):

const result = records.reduce((array, currValue) => {
    //do stuff
    return array
}, [])

这是我尝试将其更改为:

const result = records.reduce(async(array, currentValue) => {
    // do stuff
    someValue = await asyncCall(currentValue)
    array.add(someValue)
    return array
}, [])

我得到的错误是“没有重载匹配这个调用”。

这对我来说似乎很有意义,因为 reduce 接受一个返回数组的回调,而异步函数返回一个回调,而不是数组。但是当我阅读其他关于如何将异步函数传递给 .reduce 的示例时,它们似乎都只是将异步函数传递给 reduce 没有问题。

以下是我查看的几个链接:

https://advancedweb.hu/how-to-use-async-functions-with-array-reduce-in-javascript/

JavaScript array .reduce with async/await

https://gyandeeps.com/array-reduce-async-await/

当我将归约函数声明为异步时,我得到了没有匹配的重载错误,这对我来说很有意义。我不确定这对其他人是否有效。

【问题讨论】:

  • 您链接的第一篇文章包含一个关键区别:您的 .reduce() 调用将返回一个 Promise(不是回调),因此您需要在 .then() 回调或其他地方收集实际结果在包装器async 函数内调用.reduce(),以便它也可以与await 一起使用。

标签: javascript asynchronous async-await reduce


【解决方案1】:

我认为最简单的方法如下

const promises = records.reduce((array, currentValue) => {
    // do stuff
    someValue = asyncCall(currentValue)
    array.add(someValue)
    return array
}, [])

const results= Promise.all(promises);

如果您的 reduce 函数的用例更复杂,请发布更多代码或创建沙箱

【讨论】:

    【解决方案2】:

    首先:reduce 可能不是最好的工具。看起来您只是将条目添加到数组中。 reduce 对于该任务过于复杂,尤其是,如果您正在执行异步操作。相反,可以在async 函数中使用的循环结构要简单得多。

    我将从reduce 开始,然后转到循环构造。

    reduce同步工作。如果你传入一个 async 函数作为它的回调,函数返回的承诺将是下一个回调看到的累加器值。所以如果reduce操作中的一个步骤需要异步并返回一个promise,之后的每一步都必须异步返回一个promise(为简单起见,最好让每一步都返回一个promise)承诺); reduce 的结果将是对最终最终值的承诺,而不是最终值本身。不能使异步调用同步,也不能使同步操作 (reduce) 等待异步结果。

    因此,您所有的回调都将处理 Promise。它看起来有点像这样:

    const result = await records.reduce(async(arrayPromise, currentValue) => {
    // −−−−−−−−−−−−^^^^^−−−−−−−−−−−−−−−−−−−−−−^^^^^^^^^^^^
        const array = await arrayPromise // <=====
        // do stuff
        someValue = await asyncCall(currentValue)
        array.push(someValue) // <==== `push` rather than `add`, presumably
        return array
    }, Promise.resolve([]))
    // ^^^^^^^^^^^^^^^^−−^
    

    当然,因为它使用await,它必须在async 函数中。否则:

    records.reduce(async(arrayPromise, currentValue) => {
        const array = await arrayPromise // <=====
        // do stuff
        someValue = await asyncCall(currentValue)
        array.push(someValue)
        return array
    }, Promise.resolve([]))
    .then(result => {
        // ...use `result` here
    })
    .catch(error => {
        // ...handle/report error here...
    })
    

    最好使用原生支持成为async 函数一部分的循环结构:

    const result = []
    for (const currentValue of records) {
        someValue = await asyncCall(currentValue)
        result.push(someValue)
    }
    // ...use `result` here...
    

    甚至

    const result = []
    for (const currentValue of records) {
        result.push(await asyncCall(currentValue))
    }
    // ...use `result` here...
    

    如果您需要在不是 async 函数的函数中执行此操作,您将显式处理一个承诺,如下所示:

    (async () => {
        const result = []
        for (const currentValue of records) {
            result.push(await asyncCall(currentValue))
        }
        return result
    })()
    .then(result => {
        // ...use `result` here
    })
    .catch(error => {
        // ...handle/report error here...
    })
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-10-03
      • 2022-10-04
      • 1970-01-01
      • 1970-01-01
      • 2012-10-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多