数组数据在嵌套异步箭头函数循环中丢失

Lah*_*ori 6 javascript ajax ecmascript-6 es6-promise arrow-functions

线程详细解释了同步与异步之间的区别以及可能的解决方案,但我已经在使用其中一种解决方案,但仍然出现错误。我想我ES在这里达到了我的理解极限,所以我真的需要关于这个问题的帮助,因为我只是不明白为什么它会丢失。下面是我在项目中使用的代码片段nuxt,但它与它没有任何关系,因为我从后端移植了这个代码片段,即express.

async fetch({store, error}) {
  let series = '', courses = [], album = {}
  store.state.courses.forEach(async course => {
    album = {...course}
    series = course.uri.split('/')[2]
    try {
     const {data: {data}} = await axios.get('http://localhost:3000/luvlyapi/videos', {
      params: {
        series  //? album id
      }
    })
    album['videos'] = data
    courses.push(album)
    console.log('loop', courses)
  } catch (err) {
    error({statusCode: err.statusCode, message: err})
  }
})
console.log({courses})
store.commit('SET_COURSES', courses)
Run Code Online (Sandbox Code Playgroud)

} 结果

您可以看到数组正在被推送,但循环结束后仍然为空。

jfr*_*d00 7

.forEach()不等待您的异步回调。它只是愉快地继续循环,您记录 的值courses,然后一段时间后,await回调内的所有操作完成,并将值放入courses。因此,这是在将数据放入变量之前查看变量的时间问题。

值得理解的是,await仅暂停本地函数执行(最近的函数范围),在您的情况下是回调.forEach()。它不会导致更高级别的任何事情暂停。而且,由于.forEach()甚至不查看回调返回的内容,因此它肯定不会查看回调返回的承诺async。因此,一旦您按下await,您的async回调就会返回一个承诺。循环.forEach()看到回调返回并立即启动循环的下一次迭代,即使您的await内部回调尚未完成。

重要的是要理解,await仅暂停本地函数,而不是其上方的任何内容,也不是任何调用者。当你的async函数到达第一个时await,该函数就会向外界返回一个承诺。为了让外部世界也停下来,它必须兑现承诺做一些事情,而事实.forEach()并非如此。

for另一方面,循环将实际函数保留在内部await,因此整个作用域会随着await. 如果您希望循环实际上用 暂停await,那么请使用for循环,而不是.forEach()循环。

例如,您可以这样做:

async fetch({store, error}) {
    let series = '',  courses = [],  album = {};
    for (let course of store.state.courses) {
        album = {...course}
        series = course.uri.split('/')[2]
        try {
            const {data: {data}} = await axios.get('http://localhost:3000/luvlyapi/videos', {
                params: {
                    series //? album id
                }
            })
            album['videos'] = data
            courses.push(album)
            console.log('loop', courses)
        } catch (err) {
            error({
                statusCode: err.statusCode,
                message: err
            })
        }
    }
    console.log({courses})
    store.commit('SET_COURSES', courses)
}
Run Code Online (Sandbox Code Playgroud)

仅供参考,您的原始实现还存在一个问题,即在同时运行的多个异步回调之间共享更高级别的作用域变量,这将导致一个回调践踏另一个回调。解决方案是要么按照我的代码示例显示并序列化异步调用,以便它们不会同时进行,要么将变量声明为异步范围的本地变量,以便每个异步回调都有自己的单独变量。