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

标签 javascript ajax ecmascript-6 es6-promise arrow-functions

<分区>

thread详细解释了同步与异步之间的区别以及可能的解决方案,但我已经在使用其中一种解决方案并且仍然出现错误。 我想我在这里达到了我的 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)

} result

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

最佳答案

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

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

重要的是要理解 await 只会暂停本地函数,不会暂停它上面的任何东西,也不会暂停任何调用者。在您的 async 函数触发其第一个 await 的那一刻,该函数向外界返回一个 promise 。对于外部世界也暂停,它必须做一些 .forEach() 没有做的 promise 。

另一方面,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)
}

仅供引用,您的原始实现还存在一个问题,即在同时进行的多个异步回调之间共享更高级别的范围变量,这会导致一个相互冲突。解决方案是要么像我的代码示例那样做并序列化异步调用,这样它们就不会同时运行,要么将变量声明为异步范围的本地变量,这样每个异步回调都有自己的独立变量.

关于javascript - 数组数据在嵌套的异步箭头函数循环中丢失,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54569588/

相关文章:

php - 如何使用 PHP 跟踪数据库表中的更新?

javascript - 转换具有不同数据类型的数组

javascript - 在 JavaScript 中,如何优雅地创建数组元素差异列表?

javascript - 如何使旋转 block 不超出该部分?

jquery - 使用 jQuery 获取数组数据循环并将其附加到组合框副本上

JQuery:ajax 请求时的 'Uncaught TypeError: Illegal invocation'

javascript - 在 React 中使用数组键迭代循环状态对象

javascript - href 不会转到其他页面

javascript - 如何在javascript中链接两个.then?

javascript - 将具有变量作为属性名称的对象推送到数组上