提问者:小点点

数组数据在嵌套的异步箭头函数循环中丢失[重复]


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

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)

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


共2个答案

匿名用户

不等待异步回调。它只是愉快地继续循环,然后记录的值,稍后,回调中的所有操作完成,然后将这些值放入中。所以,这是一个时间问题,在数据被放入变量之前,你要查看变量。

值得理解的是,仅暂停本地函数的执行(最接近的函数作用域),在您的示例中是回调。它不会导致更高级别的任何东西暂停。而且,由于甚至不查看您的回调返回的内容,因此它肯定不会查看回调返回的承诺。因此,只要您点击,您的回调就会返回一个承诺。循环看到回调返回,并立即启动循环的下一次迭代,即使回调中的尚未完成。

重要的是要理解只暂停本地函数,而不暂停它上面的任何东西,也不暂停任何调用方。当函数碰到它的第一个时,该函数将向外部世界返回一个承诺。外部世界也要暂停,它必须对承诺做一些没有做的事情。

另一方面,循环将保留在实际函数中,因此整个作用域用暂停。如果您希望循环实际上用暂停,那么请使用循环,而不是循环。

例如,您可以这样做:

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

仅供参考,您的原始实现还存在一个问题,即在多个异步回调中共享更高级的作用域变量,这些变量同时运行,这将导致一个变量在另一个变量上跳转。解决方案是,要么像我的代码示例所示那样,序列化异步调用,这样它们就不会同时运行,要么将变量声明为异步作用域的本地变量,这样每个异步回调都有自己的独立变量。

匿名用户

尝试如下使用Promise.all(从head编写代码)

null

async fetch({ store, error }) {
  let series = '', courses = [], album = {}
  let pr = store.state.courses.map(course => {
    return new Promise(resolve => {
      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)
        resolve();
      } catch (err) {
        error({ statusCode: err.statusCode, message: err })
      }
    })
  });

  await Promise.all(pr);

  console.log({ courses })
  store.commit('SET_COURSES', courses)
}