Vue中如何优雅的捕获 Promise 异常详解

 更新时间:2022年10月27日 16:42:46   作者:WujieLi  
这篇文章主要为大家介绍了Vue中如何优雅的捕获 Promise 异常详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

常规的异常捕获方式

在 Promise 提供了一个 .catch 方法用来捕获异常,假设有很多异步请求,通常会把 .catch 方法放在链式调用的最末尾。正常情况下末尾的 .catch 不会被触发,但当前面的任何一个 Promise rejected 之后,.catch 就可以捕获到异常

promiseFunction1({
  year: unref(year),
})
  .then((res) => {
    if (res.status === 200) {
      return promiseFunction2(res.data?.name || "");
    }
  })
  .then((res) => {
    if (res.status === 200) {
      const getUserInfo = userInfoResult.data;
      // ... 具体操作
    }
  })
  // 异常捕获
  .catch((error) => console.error(error));

如果使用 Promise 的语法糖 async / await 的话,可以使用更符合直觉的 try...catch 捕获异常,上面这个请求例子就可以修改为

async function handleUserInfo() {
  try {
    const userResult = await promiseFunction1({ year: unref(year) });
    if (userResult.status !== 200) return;
    const userInfoResult = await promiseFunction2(res.data?.name || "");
    if (userInfoResult.status !== 200) return;
    getUserInfo = userInfoResult.data;
    // ... 具体操作
  } catch (error) {
    console.error(error);
  }
}

不管是 .then 方法还是 try...catch 都需要增加一些代码操作,最重要的是可能会忘记捕获异常,所以下面介绍两个更好一些的解决方案

好一些的方式:await-to-js

await-to-js 是一个大佬对 async / await 返回内容进行的一层封装,在不用 try...catch 的方式下也能进行异常捕获

在使用前需要先引入这个依赖:npm i await-to-js,下面我们来改写简化一下之前的异常捕获方式

import to from 'await-to-js';
async function handleUserInfo() {
    const [userError, userResult] = await promiseFunction1({ year: unref(year) })
    if (userResult.status !== 200) return 
    const [userInfoError, userInfoResult] = await promiseFunction2(res.data?.name || "")
    if (userInfoResult.status !== 200) return 
    getUserInfo = userInfoResult.data
    // ... 具体操作
}

await-to-js 的实现也就短短几行代码,本质就是对 Promise 的 .then.catch 返回结果进行组合,然后整体作为一个 Promise 再返回出去

export function to<T, U = Error> (
  promise: Promise<T>,
  errorExt?: object // 传递给 err 对象的附加信息
): Promise<[U, undefined] | [null, T]> {
  return promise
    .then<[null, T]>((data: T) => [null, data])
    .catch<[U, undefined]>((err: U) => {
      if (errorExt) {
        const parsedError = Object.assign({}, err, errorExt);
        return [parsedError, undefined];
      }
      return [err, undefined];
    });
}
export default to;

虽然 await-to-js 简化了代码,但还是需要引入依赖,对请求进行一层包裹,还是稍微麻烦了一点,如果我们对异常处理没有特殊处理的需要,仅仅只是捕获并且抛出,为了追求更简洁的代码;

或者项目中有非常多的地方没有异常捕获,需要一个一个的手工增加非常麻烦,针对这两种情况,还有没有更好的办法呢?

更好的方式:全局捕获

在 Vue2 的全局配置中提供了一个 errorHandler 钩子可以用于捕获全局异常,但是最低版本要求 2.2.0+

errorHandler 第一个参数 err 是具体的错误信息,第二个参数 vm 是 Vue 组件信息,第三个参数 info 是 Vue 特定的错误信息,比如错误所在的生命周期钩子。一般为了捕获 Vue 特定的 info 信息,在内部处理时还会加上一层 nextTick ,确保捕获的是 DOM 渲染完成之后的信息。另外最好在根据不同环境配置判断是否需要捕获异常,增加程序的灵活性

// errorHandler 使用示例
import Vue from 'vue'
// 配置项形式:'development' | ['development', 'production']
const { errorLog: needErrorLog } = settings
// 根据配置判断什么环境下需要捕获异常
function checkNeedErrorLog() {
  const env = process.env.NODE_ENV
  if (isString(needErrorLog)) {
    return env === needErrorLog
  }
  if (isArray(needErrorLog)) {
    return needErrorLog.includes(env)
  }
  return false
}
// 全局异常捕获
if (checkNeedErrorLog()) {
  Vue.config.errorHandler = function (err, vm, info) {
    Vue.nextTick(() => {
      console.error(`[${projectName}]: ${err}。`, `Vue info: ${info}`, vm)
    })
  }
}

根据官网的描述,不同的 Vue 版本捕获的信息不同,所以建议最好是更新 Vue 2.6.0 以上的版本,这样就可以全局捕获到 Promise 和 async / await 抛出的异常了,

从 2.2.0 起,errorHandler 钩子也会捕获组件生命周期钩子里的错误。同样的,当这个钩子是 undefined 时,被捕获的错误会通过 console.error 输出而避免应用崩溃

从 2.4.0 起,errorHandler 钩子也会捕获 Vue 自定义事件处理函数内部的错误

从 2.6.0 起,errorHandler 钩子也会捕获 v-on DOM 监听器内部抛出的错误。另外,如果任何被覆盖的钩子或处理函数返回一个 Promise 链 (例如 async 函数),则来自其 Promise 链的错误也会被处理

在 Vue3 中,除了提供 errorHandler 钩子外,还提供了 warnHandler 钩子,两个钩子的用法相同,区别是是 warnHandler 只在开发环境生效,生产环境会被忽略

app.config.warnHandler = function(msg, vm, trace) {
  // `trace` 是组件的继承关系追踪
}

以上就是Vue中如何优雅的捕获 Promise 异常详解的详细内容,更多关于Vue Promise 异常捕获的资料请关注脚本之家其它相关文章!

相关文章

  • vue3中使用vuedraggable实现拖拽el-tree数据分组功能

    vue3中使用vuedraggable实现拖拽el-tree数据分组功能

    这篇文章主要介绍了vue3中使用vuedraggable实现拖拽el-tree数据分组功能,可以实现单个拖拽、双击添加、按住ctrl键实现多个添加,或者按住shift键实现范围添加,添加到框中的数据,还能拖拽排序,需要的朋友可以参考下
    2024-02-02
  • Vue 禁用浏览器的前进后退操作

    Vue 禁用浏览器的前进后退操作

    这篇文章主要介绍了Vue 禁用浏览器的前进后退操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-09-09
  • 详解Vue2中组件间通信的解决全方案

    详解Vue2中组件间通信的解决全方案

    Vue中组件这个特性让不少前端er非常喜欢,我自己也是其中之一,它让前端的组件式开发更加合理和简单。下面这篇文章主要给大家介绍了关于Vue2中组件间通信的解决全方案,文中通过示例代码介绍的非常详细,需要的朋友们下面来一起看看吧。
    2017-07-07
  • vue动态注册组件实例代码详解

    vue动态注册组件实例代码详解

    写本篇文章之前其实也关注过vue中的一个关于加载动态组件is的API,最开始研究它只是用来实现一个tab切换的功能,需要的朋友可以参考下
    2019-05-05
  • 前端构建工具Webpack、Vite区别有哪些

    前端构建工具Webpack、Vite区别有哪些

    Webpack和Vite是两种主流的前端构建工具,它们在功能、性能和使用场景上有所不同,Webpack提供丰富的功能和配置,适合大型复杂项目,但可能导致启动和构建速度较慢,Vite基于ES模块,支持快速的热替换,适合小型或中等项目,需要的朋友可以参考下
    2024-10-10
  • vue-resource 拦截器使用详解

    vue-resource 拦截器使用详解

    本篇文章主要介绍了vue-resource 拦截器使用详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-02-02
  • vue之elementUi的el-select同时获取value和label的三种方式

    vue之elementUi的el-select同时获取value和label的三种方式

    这篇文章主要介绍了vue之elementUi的el-select同时获取value和label的三种方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02
  • vue-cli2 构建速度优化的实现方法

    vue-cli2 构建速度优化的实现方法

    这篇文章主要介绍了vue-cli2 构建速度优化的实现方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-01-01
  • vue router权限管理实现不同角色显示不同路由

    vue router权限管理实现不同角色显示不同路由

    本文主要介绍了vue router权限管理实现不同角色显示不同路由,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • vue中data和data()的区别说明

    vue中data和data()的区别说明

    这篇文章主要介绍了vue中data和data()的区别说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03

最新评论