由于 Nuxt 的 fetch hooks 不能并行运行,我需要一种方法来取消导航到其他路由时在 fetch hook 中完成的请求,这样用户在登陆导航到的主页时不必等待第一次 fetch 完成其他。所以我找到了这种方法:How to cancel all Axios requests on route change
所以我为 Next 创建了这些插件文件:
router.js
export default ({ app, store }) => {
// Every time the route changes (fired on initialization too)
app.router.beforeEach((to, from, next) => {
store.dispatch('cancel/cancel_pending_requests')
next()
})
}
axios.js
export default function ({ $axios, redirect, store }) {
$axios.onRequest((config) => {
const source = $axios.CancelToken.source()
config.cancelToken = source.token
store.commit('cancel/ADD_CANCEL_TOKEN', source)
return config
}, function (error) {
return Promise.reject(error)
})
}
和一个用于取消令牌的小型 vuex 存储:
export const state = () => ({
cancelTokens: []
})
export const mutations = {
ADD_CANCEL_TOKEN (state, token) {
state.cancelTokens.push(token)
},
CLEAR_CANCEL_TOKENS (state) {
state.cancelTokens = []
}
}
export const actions = {
cancel_pending_requests ({ state, commit }) {
state.cancelTokens.forEach((request, i) => {
if (request.cancel) {
request.cancel('Request canceled')
}
})
commit('CLEAR_CANCEL_TOKENS')
}
}
现在这种方法工作正常,我可以看到请求在路由更改时被 499 取消,但是,它在我的开发工具控制台中充斥着“获取错误()”错误。是否有一些首选/更好的方法来做到这一点?
此处获取钩子的示例:
async fetch () {
await this.$store.dispatch('runs/getRunsOverview')
}
分派动作示例:
export const actions = {
async getRunsOverview ({ commit }) {
const data = await this.$axios.$get('api/frontend/runs')
commit('SET_RUNS', data)
}
}
编辑:我忘了提到我在这里使用 fetch 并将 fetchOnServer
设置为 False
来向用户显示一些加载占位符。
主要问题是充满错误的控制台,但我也可以看到它也进入了我的模板中的 $fetchState.error
分支,它在路由切换之前显示带有“出现问题”文本的 div。
编辑2:
仔细查看此错误的来源,它是 fetch.client.js
目录中的 mixin 文件 .nuxt/mixins
。粘贴获取函数代码如下:
async function $_fetch() {
this.$nuxt.nbFetching++
this.$fetchState.pending = true
this.$fetchState.error = null
this._hydrated = false
let error = null
const startTime = Date.now()
try {
await this.$options.fetch.call(this)
} catch (err) {
if (process.dev) {
console.error('Error in fetch():', err)
}
error = normalizeError(err)
}
const delayLeft = this._fetchDelay - (Date.now() - startTime)
if (delayLeft > 0) {
await new Promise(resolve => setTimeout(resolve, delayLeft))
}
this.$fetchState.error = error
this.$fetchState.pending = false
this.$fetchState.timestamp = Date.now()
this.$nextTick(() => this.$nuxt.nbFetching--)
}
也尝试按照@kissu 在评论中的建议使用 async/await 进行所有操作,但没有运气:/