Jinuss's blog Jinuss's blog
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript高级程序设计》
    • 《Vue》
    • 《React》
    • 《Git》
    • JS设计模式总结
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • 学习
  • 实用技巧
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

东流

前端可视化
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript高级程序设计》
    • 《Vue》
    • 《React》
    • 《Git》
    • JS设计模式总结
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • 学习
  • 实用技巧
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 概览

    • 概览
    • vue3插件原理
    • vue3中的错误处理方案
      • 概述
      • 错误处理设计
        • ErrorCodes和ErrorTypeStrings 类型
        • callWithErrorHandling 方法
        • callWithAsyncErrorHandling 方法
        • handleError 方法
        • onErrorCaptured
  • 响应式系统

  • runtime运行时

  • runtime-core

  • compiler编译

  • 《Vue3源码》笔记
  • 概览
东流
2024-09-02
目录

vue3中的错误处理方案

# 概述

在设计一个框架时,如何处理错误是必不可少的环节。错误在程序开发中避无可避,那么出现错误时,至少要保证程序不会崩溃。合理的错误处理方案会大大增强框架的健壮性,覆盖异常场景,提高系统的可用性。

本文将探讨vue3中的错误处理设计。

# 错误处理设计

vue3中的错误处理逻辑集中在程序运行时,源码部分位于runtime-core\src\errorHandling.ts。其内部封装了两个工具函数:callWithErrorHandling和callWithAsyncErrorHandling,用于处理函数调用中的错误,它们在vue3的响应式系统和组件生命周期中扮演着重要角色,通常情况下只是vue3内部调用。

# ErrorCodes和ErrorTypeStrings 类型

vue3的错误处理定义了错误码和错误类型,用来标识错误,方便排查问题。

# callWithErrorHandling 方法

callWithErrorHandling函数用于同步函数调用时捕获错误,会在函数执行期间捕获并处理可能出现的异常情况或同步错误 其实现如下:

function callWithErrorHandling(fn, instance, type, args) {
  try {
    return args ? fn(...args) : fn();
  } catch (err) {
    handleError(err, instance, type);
  }
}
1
2
3
4
5
6
7

上述示例很好理解,就是用到try、catch取执行fn函数,并返回fn函数执行的结果;在catch中捕获错误,调用handleError函数

# callWithAsyncErrorHandling 方法

callWithAsyncErrorHandling函数用于处理异步函数调用中的错误,它能够捕捉和处理Promise的reject错误。 其实现如下

function callWithAsyncErrorHandling(fn, instance, type, args) {
  //fn:函数 instance:vue实例 type:类型 args:传递给fn的参数,下同
  if (isFunction(fn)) {
    const res = callWithErrorHandling(fn, instance, type, args);
    if (res && isPromise(res)) {
      res.catch((err) => {
        handleError(err, instance, type);
      });
    }
    return res;
  }
  if (isArray(fn)) {
    const values = [];
    for (let i = 0; i < fn.length; i++) {
      values.push(callWithAsyncErrorHandling(fn[i], instance, type, args));
    }
    return values;
  } else if (true) {
    warn2(
      `Invalid value type passed to callWithAsyncErrorHandling(): ${typeof fn}`
    );
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

上面这段代码也不难理解,首先判断fn是否是函数,若是函数,则调用callWithAsyncErrorHandling,然后判断其返回值是否是Promise,若是Promise,则在其catch方法中绑定handleError方法;若fn则是数组,则遍历fn,循环调用callWithAsyncErrorHandling;如果fn既不是函数又不是数组,则调用warn2,抛出异常。

# handleError 方法

上述两个工具函数在捕获到错误后,都会调用handleError处理错误,其作用就是找出错误的上下文,指明错误的地方,以及处理错误回调。

其实现如下:

function handleError(err, instance, type, throwInDev = true) {
  const contextVNode = instance ? instance.vnode : null;
  if (instance) {
    let cur = instance.parent;
    const exposedInstance = instance.proxy;
    const errorInfo = true
      ? ErrorTypeStrings[type]
      : `https://vuejs.org/error-reference/#runtime-${type}`;
    while (cur) {
      const errorCapturedHooks = cur.ec;
      if (errorCapturedHooks) {
        for (let i = 0; i < errorCapturedHooks.length; i++) {
          if (
            errorCapturedHooks[i](err, exposedInstance, errorInfo) === false
          ) {
            return;
          }
        }
      }
      cur = cur.parent;
    }
    const appErrorHandler = instance.appContext.config.errorHandler;
    if (appErrorHandler) {
      pauseTracking();
      callWithErrorHandling(appErrorHandler, null, 10 /* APP_ERROR_HANDLER */, [
        err,
        exposedInstance,
        errorInfo,
      ]);
      resetTracking();
      return;
    }
  }
  logError(err, type, contextVNode, throwInDev);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

handleError方法接受四个参数err, instance, type, throwInDev。分别是错误信息、vue 实例、错误类型、是否在环境中抛出错误。默认都会抛出异常。若instance存在,则判断当前节点的父节点,在父组件中去捕获并处理子组件的错误。下面会介绍onErrorCaptured。

handleError中还会判断全局变量上是否挂载了errorHandler函数,如果系统的前端侧需要处理错误日志,监测前端错误的,就可以在main.js这样写,

app.config.errorHandler = (p) => {
  const [err, exposedInstance, errorInfo] = p; //对应handleError中的变量
};
1
2
3

# onErrorCaptured

cur.ec实质上是获取组件的生命周期函数onErrorCaptured,这个钩子函数主要用于捕获和处理其所有子组件的抛出的错误,以便在更高层级的组件中进行错误处理。

用法一般如下

errorCaptured(err, instance, info) {
    // err:处理错误  info:包含关于错误的额外信息,如发生在哪个生命周期钩子

    /*** 逻辑代码 */

    return false; // true:错误会继续传播 false:可以阻止错误继续向上抛出
  },
1
2
3
4
5
6
7
编辑 (opens new window)
上次更新: 2024/12/03, 14:43:37
vue3插件原理
Proxy对象代理

← vue3插件原理 Proxy对象代理→

最近更新
01
GeoJSON
05-08
02
Circle
04-15
03
CircleMarker
04-15
更多文章>
Theme by Vdoing | Copyright © 2024-2025 东流 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式