如何捕获 async 函数中的错误?

// 登录
  async login({ commit }, params) {
    const loginFormData = new FormData()
    Object.keys(params).forEach(key => {
      loginFormData.append(key, params[key])
    })
    const useVCode = 'vcode' in params
    try {
      // 等待 ajax 请求完成
      const res = await axios.post(
        `/api/login/with/${useVCode ? 'vcode' : 'password'}`,
        loginFormData
      )
      const data = res.data
      if (data.success) {
        Message.success('登录成功')
        Object.keys(data.data).forEach(key => {
          Vue.$cookies.set(key, data.data[key])
        })
        commit(constants.LOGIN, data.data)
      } else {
        Message.error(data.message)
      }
    } catch (err) {
      console.log(err)
    }
  }

在项目的开发过程中用到了 async 函数,如何在调用该函数时捕获 axios 中抛出的错误?

    // 登录
    onSubmit() {
      this.$refs.loginForm.validate(valid => {
        if (valid) {
          this.loading = true
          const params = {
            mobile: this.loginForm.mobile,
            [this.useVCode ? 'vcode' : 'password']: this.useVCode
              ? this.loginForm.vCode
              : MD5(this.loginForm.password)
          }
          // 如何在此处捕获 async 函数中 axios 的报错
          // 比如说网络原因导致 axios 请求无法完成
          // 根据 axios 的报错跳转不同的路由
          this.login(params).then(() => {
            this.loading = false
            this.$refs.loginForm.resetFields()
            const back = sessionStorage.getItem('back')
            this.$router.push(back)
          })
        }
      })
    }
阅读 5.5k
3 个回答

这一段是官方“Handling Errors”的示例,是基于 Promise 的例子:

axios.get('/user/12345')
  .catch(function (error) {
    if (error.response) {
      // The request was made and the server responded with a status code
      // that falls out of the range of 2xx
      console.log(error.response.data);
      console.log(error.response.status);
      console.log(error.response.headers);
    } else if (error.request) {
      // The request was made but no response was received
      // \`error.request\` is an instance of XMLHttpRequest in the browser and an instance of
      // http.ClientRequest in node.js
      console.log(error.request);
    } else {
      // Something happened in setting up the request that triggered an Error
      console.log('Error', error.message);
    }
    console.log(error.config);
  });

总体来说,出错分三种情况

  1. 服务器端出错,判断 error.response
  2. 请求时出错判断 error.request,并从中获取错误信息
  3. 其它情况下的错误

示例是基于 Promise 的,但题主的写法是基于 async/await 的,所以需要将 .catch(...) 改为 try ... catch ... 写法,即

try {
    const res = await axios.post(...);
} catch (error) {
    if (error.response) {...}
    else if (error.request) {...}
    else {...}
}

不过题主在 catch ... 代码块中写的是 console.log(err),错误在 login() 内部消化了,那么外面调用 login() 的时候就不知道里面是否出错。

如果需要知道 login() 里面出了什么问题,有两种方法,

一种是在 login() 中不作处理,把问题留给外面来处理,比如

    async login({ commit }, params) {
        // ...
        // 不使用 try ... catch ... 包装
        const res = await axios.post(
            `/api/login/with/${useVCode ? "vcode" : "password"}`,
            loginFormData
        );
        // ...
    }
    onSubmit() {
        this.$refs.loginForm.validate(async valid => {
            // ~~~~~~~~~~~~~~~~~~~~~~~^^^^^~~~~~~~~~~~
            if (valid) {
                // ....
                try {
                    const loginResult = await this.login(params);
                    // ~~~~~~~~~~~~~~~~~^^^^^~~~~~~~~~~~~~~~~~~~
                    // 不需要 then 了,直接往下写,因为 await
                    this.loading = false;
                    // ...
                } catch (err) {
                    if (err.response) { /*...*/ }
                    else if (err.request) { /*...*/ }
                    else { /*...*/ }
                }
                // ....
            }
        });
    }

另一种方法是在内部处理了之后,将错误信息封装给外面使用

    async login({ commit }, params) {
        // ...
        const result = {
            type: 0,        // 自己定义,比如 0 表示没有错,1 表示 response 错误等
            message: "",    // 看是否需要
            data: null,     // 看是否需要携带数据
        };

        try {
            const res = await axios.post(
                `/api/login/with/${useVCode ? "vcode" : "password"}`,
                loginFormData
            );
            return result;
        } catch (err) {
            console.log(err);
            if (err.response) {
                result.type = 1;
                // ...
            } else if (err.request) { /*...*/ } else { /*...*/ }
            return result;
        }
        // ...
    }
    onSubmit() {
        this.$refs.loginForm.validate(valid => {
            if (valid) {
                // ....
                this.login(params).then(result => {
                    // ~~~~~~~~~~~~~~~~~^^^^^^~~~~~
                    // 使用内部输出的 DTO
                    swtich(result.code) {
                        // ...
                    }
                });
                // ....
            }
        });
    }

再创建一个Promise对象对执行的方法进行包裹

function fn() {
return new Promise((resolve, reject)=> {
    //内部是你执行的逻辑
    //以resolve(data)返回结果并结束逻辑
    //以reject(err)在你想要处理的位置返回错误数据并结束逻辑
    })
}

fn().then(res=>{
    //成功返回
}).catch(err=>{
    //处理错误
})

出错了可以 throw 。

你在 login 里已经把错误都处理了,外面就不知道了。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题