这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)
}
您可以看到数组正在被压入,但一旦循环结束仍然是空的。
.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)
}
仅供引用,您的原始实现还存在一个问题,即在同时进行的多个异步回调之间共享更高级别的范围变量,这会导致一个相互冲突。解决方案是要么像我的代码示例那样做并序列化异步调用,这样它们就不会同时运行,要么将变量声明为异步范围的本地变量,这样每个异步回调都有自己的独立变量.