关于router.beforeEach 调用 axios 的问题

现在我有一个需求在所有页面,显示前需要做一个远程的授权验证
我用router + axios 来做的,这个代码在执行的过程中:

check() 第一次没有执行axios代码
所有代码都走完,才会走axios的代码

难到是执行顺序不吗?
但我加了await 正常不是应该 check()一次性全走完的嘛

不知道哪里写错了


router/index.js

import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import check from '../js/check'

Vue.use(Router)

const router = new Router({
  routes: [
    {
      path: '/',
      name: 'HelloWorld',
      component: HelloWorld
    }
  ]
})

router.beforeEach((to, from, next) => {
  alert('123')
  alert(check())   ----->show msg is  [object:promise]
})

export default router

http://test.com/name=123 1

return msg

{
    "status": 0,
    "msg": "ok",
    "data": null
}

js/check.js

import axios from 'axios'

let Url = 'http://test.com.cn/name=123'

export default  async function check () {

  let aa

  await axios.get(Url)
    .then(function (response) {
      aa = response.data
      console.log(response)
    })
    .catch(function (error) {
      console.log(error)
    })

  return aa
}
阅读 5.3k
1 个回答

Vue Router 的 beforeEach 的参数是一个 NavigationGuard 类型的参数,这是一个函数,允许三个参数。其中最后一个 next 参数主要用于完成之后的回调(异步操作完成之后调用),它也允许返回一个 Promise 来代替 next(具体看 NavigationGuard 的文档)。

axios 是一个异步过程,在没有进行异步等待的时候,它会在下一句代码之后才完成。也就是:

router.beforeEach((to, from, next) => {
  alert('123')
  alert(check())  // 这里 check() 还没完成
                  // 就已经执行到 alert 了,因为 check 是一个异步过程
                  // 所以 alert 看到的是一个 Promise 对象
})

check() 是一个 async 函数,所以一定会返回一个 Promise,如果要在 Promise 完成之后再进行操作,可以在其对象的 .then() 中处理,也可以使用 await 来异步等待。但要注意的是 await 需要在 async 函数中使用。所以

router.beforeEach((to, from, next) => {
    alert('123')
    check().then((res) => {
        alert(res);
        next(true); // 这里调用 next 表示异步操作完成,继续后续过程
    });  // 注意,没有处理 reject 的情况,所以异步逻辑是不完整的(分支非完全覆盖)
})

不使用 next,可以返回 Promise 链的结果。但要注意,任何分支的最后一个 Promise 应该包裹一个 boolean 值

return check()
    .then((res) => {
        // 处理 res
        return true;   // 和 next(true) 等效
    })
    .catch(() => {
        // 处理出错的情况
        return false;  // 和 next(false) 等效
    })

可以使用 await

router.beforeEach(async (to, from, next) => {
    alert('123');
    try {
        const res = await checl();
        // 使用 res
        return true;
    } catch (err) {
        // 处理错误
        return false;
    }
})

参考阅读:


补充一下,check() 内部的处理还可以优化一下

import axios from "axios";

let url = "http://test.com.cn/name=123";

export default async function check() {
    const response = await axios.get(url)
        // 避免使用 try ... catch 包裹,使用 .catch() 把异常处理成正常的数据
        // 这里没有返回,也就是 return undefiend;
        .catch(err => {
            console.log(err);
        });

    // response 不存在(被 catch 处理过)时返回 undefined
    // 存在时返回其 data 属性值
    return response?.data;
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题