vue中@Action的异常处理你了解吗?(实践)

2,552 阅读5分钟

前言


星期三女朋友和堂姐在家做的美食,走到四五楼闻到香味:香死啦~


回味登陆CODE

Login.vue

现象:密码输入错误。

分析:应该是接口没有返回data,只是在if(data) { this.loading = false },所以就算没有data也需要设为false;或者走了catch

当然我看到页面这种情况,也只是猜的,因为我也好久没看到之前写的登录逻辑。

先来欣赏之前写的代码。

/**
* Login.vue
* 登陆按钮点击事件
*/
private handleLogin() {
    (this.$refs.loginForm as ElForm).validate(async (valid: boolean) => {
      if (valid) {
        this.loading = true;
        await UserModule.Login(this.loginForm);

        setTimeout(() => {
          this.loading = false;
        }, 0.5 * 1000);

        this.$router.push({
          path: this.redirect || "/",
          query: this.otherQuery
        });
      } else {
        return false;
      }
    });
  }

欣赏心得:

if (valid)里面不管登录成功或者失败,都将loading视为false,这是对的;但是没有用一个变量接收这个结果await UserModule.Login,如果一直await不到结果,就不会走下面的代码,不管成功失败都跳路由(应该是成功的时候才跳路由吧,之前真是能完成功能就好,随便应付)

继续走下去,等会在上修改后的代码。

Store.user.ts

Login.vue上面的代码看,主要看这段代码:await UserModule.Login(this.loginForm);

  @Action
  public async Login(userInfo: { username: string, password: string }) {
    let { username, password } = userInfo
    username = username.trim()

    const {data}  = await login({ username, password })
    setToken(data.accessToken)
    this.SET_TOKEN(data.accessToken)
    this.SET_NAME(username)
  }

欣赏心得:

没有try、catch住await login(),没有报错了,下面就不会执行下去。

我打印了data,发现打印不出来,很明显await login()的时候便报错了。

login请求

继续追究下去,login请求

// Response interceptors
service.interceptors.response.use(
  (response) => {
    const res = response.data
    if (res.code !== 20000) {
      return Promise.reject(new Error(res.message || 'Error'))
    } else {
      return response.data
    }
  }

发现走的是return Promise.reject(new Error(res.message || 'Error')),因为code:20001

@Action({rawError:true})

我打开控制台,发现:

百度ERR_ACTION_ACCESS_UNDEFINED: Are you trying to access this.someMutation() or this.someGetter inside

解决方案

@Action({rawError:true}):即暴露出原生 error。

最后try、catch下错误就解决了错误。

写在这基本就完结了问题错误。

但是我相信很多同学跟我一样,想知道@Action({rawError:true})是干嘛的,那请继续往下看我分析。

vue中@Action的异常处理

我们先来看一个知识点

  • 在某行代码有错误抛出后,后面的代码都不会被执行,直接阻断
  • try-catch 语句里的代码有一行有错误,后面也阻断,但是跳出 catch 语句后面的代码依然可以执行,因为抛出的错误被 catch 接到了
try {
    test()
    console.log('after-test');
  } catch (e) {
    console.log('catch-error', e);
  }
  console.log('after-trycatch');
  function test() {
    throw new Error()
  }

test函数执行,throw Error错误,被catch接住,便打印了catch-error + 抛出的错误,继续走下面的输出after-trycatch

OK,相信有了上面的了解,再来看下面的代码,会更清楚点。

store.user

  @Action
  public async Login(userInfo: { username: string, password: string }) {
    let { username, password } = userInfo
    username = username.trim()
    this.SET_NAME(username)
  
    const {data}  = await login({ username, password })
    setToken(data.accessToken)
    this.SET_TOKEN(data.accessToken)
  }

Login.vue

private handleLogin() {
  (this.$refs.loginForm as ElForm).validate(async (validboolean) => {
    if (valid) {
      this.loading = true;
      try {
        await UserModule.Login(this.loginForm);
      } catch (e) {
        console.log(e);
      }

      setTimeout(() => {
        this.loading = false;
      }, 0.5 * 1000);
    } else {
      return false;
    }
  });
}

现象:此时 catch 住的 error 并非项目里由 axios 抛出的 requestError 类型(该类型包含 isHandled 属性)

打印 error:抛出两个异常

  • 一个是ERR_ACTION_ACCESS_UNDEFINED
  • 一个是error:无法链接或出错。其中第二个是 requestError 类型的。但是基于上面知识点中所说的代码里 throw error,后面的代码应该不执行的,但是却执行了 setToken(data.accessToken),从而导致 mutation 报错,说明@Action 做了一些工作。

分析源码: 那么页面 catch 住的是什么 error 呢,查看vuex-module-decorators中关于@Action的源码:

可知:@Action 在不给 rawError 置为 true 时,会 new 一个新的 Error,并且带上 aciton 里抛出的错误,包裹到一起抛出,因此页面 catch 住的 error 是@Action 抛出的错误,打印就会看到原 error 的信息

总结:这也就是为什么页面上把两个错误一起抛出来了。一个是action抛出来、一个是请求走new thorw抛出来,合并打印出来。

解决方法: 加rawError属性,@Action({rawError:true}),即暴露出原生 error。

好,我们加上试一下

可以看到只剩下原生的error,action的错误不会抛出来了。

Login.vue代码

store.user代码

!__!:
一天一行代码,干饭啦!

原文链接

juejin.cn/post/693647…

参考文档

ERR_ACTION_ACCESS_UNDEFINED: Are you trying to access this.someMutation() or this.someGetter inside

ue中@Action的异常处理