此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)
您可以看到数组已被推送,但循环结束后仍然为空。
答案 0 :(得分:3)
.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)
}
仅供参考,您的原始实现还存在一个问题,即在多个异步回调之间共享更高级别的范围内的变量,这些回调同时处于运行状态,这将导致一个踩到另一个。解决方案是要么像我的代码示例所示并序列化异步调用,以使其不在同一时间运行,要么将变量声明为异步作用域的局部变量,以便每个异步回调都具有自己的单独变量。
答案 1 :(得分:0)
尝试按以下方式使用Promise.all(从head编写代码)
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)
}
问题在于在forEach内部使用await-不会等待...更多详细信息here