最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

源碼剖析Vue3中如何進行錯誤處理

 更新時間:2024年01月29日 10:39:49   作者:云浪  
錯誤處理是框架設(shè)計的核心要素之一,框架的錯誤處理好壞,直接決定用戶應(yīng)用程序的健壯性以及用戶開發(fā)應(yīng)用時處理錯誤的心智負擔(dān),本文將從源碼入手,剖析一下Vue3中是如何進行錯誤處理的,需要的可以參考下

錯誤處理

錯誤處理是框架設(shè)計的核心要素之一。框架的錯誤處理好壞,直接決定用戶應(yīng)用程序的健壯性以及用戶開發(fā)應(yīng)用時處理錯誤的心智負擔(dān)。同時,Vue 作為一個基礎(chǔ)地前端框架,也提供了統(tǒng)一地全局錯誤處理接口,用戶可以通過該接口(errorhandler)注冊自定義的錯誤處理程序來全局地處理框架產(chǎn)生的所有異常。

Vue3 中提供了兩種處理異常的函數(shù),同步異常處理函數(shù)(callWithErrorHandling)和異步異常處理函數(shù)(callWithAsyncErrorHandling)。異步異常處理函數(shù)是在同步異常處理函數(shù)的基礎(chǔ)上實現(xiàn)的。

// packages/runtime-core/src/errorHandling.ts

export function callWithErrorHandling(
  fn: Function,
  instance: ComponentInternalInstance | null,
  type: ErrorTypes,
  args?: unknown[]
) {
  let res
  try {
    res = args ? fn(...args) : fn()
  } catch (err) {
    handleError(err, instance, type)
  }
  return res
}

本篇文章的源碼均摘自 Vue.js 3.2.45

從整體上來看,callWithErrorHandling 函數(shù)的實現(xiàn)是比較簡單的,就是對 try catch 的封裝。catch 捕獲到的異常統(tǒng)一由 handleError 函數(shù)來處理。

// packages/runtime-core/src/errorHandling.ts

export function handleError(
  err: unknown,
  instance: ComponentInternalInstance | null,
  type: ErrorTypes,
  throwInDev = true
) {
  // 省略其他代碼
  logError(err, type, contextVNode, throwInDev)
}
function logError(
  err: unknown,
  type: ErrorTypes,
  contextVNode: VNode | null,
  throwInDev = true
) {
  if (__DEV__) {
    // 省略其他代碼
  } else {
    // recover in prod to reduce the impact on end-user
    console.error(err)
  }
}

在 handleError 中會將捕獲到的異常輸出來。

// packages/runtime-core/src/errorHandling.ts

export function callWithAsyncErrorHandling(
  fn: Function | Function[],
  instance: ComponentInternalInstance | null,
  type: ErrorTypes,
  args?: unknown[]
): any[] {
  if (isFunction(fn)) {
    const res = callWithErrorHandling(fn, instance, type, args)
    if (res && isPromise(res)) {
      res.catch(err => {
        handleError(err, instance, type)
      })
    }
    return res
  }

  const values = []
  for (let i = 0; i < fn.length; i++) {
    values.push(callWithAsyncErrorHandling(fn[i], instance, type, args))
  }
  return values
}

異步異常處理函數(shù)(callWithAsyncErrorHandling),是基于同步異常處理函數(shù)(callWithErrorHandling)實現(xiàn)的,如果傳入的參數(shù)是函數(shù)數(shù)組(Function[]),則會遍歷這個函數(shù)數(shù)組,遞歸調(diào)用異步異常處理函數(shù)(callWithAsyncErrorHandling),將返回的結(jié)果保留到數(shù)組中(values),最后返回這個數(shù)組。

在異步異常處理函數(shù)中(callWithAsyncErrorHandling) ,它通過判斷傳入函數(shù)的返回值(res)是否為對象,并且是否有 then 、catch 回調(diào)來判斷返回值(res)是否為 Promise 實例。這種判斷是否為 Promise 實例的方式在我們平時的開發(fā)中也可以借鑒一下。

// packages/shared/src/index.ts

export const isFunction = (val: unknown): val is Function =>
  typeof val === 'function'

export const isObject = (val: unknown): val is Record<any, any> =>
  val !== null && typeof val === 'object'

// 判斷是否為 Promise 實例
export const isPromise = <T = any>(val: unknown): val is Promise<T> => {
  return isObject(val) && isFunction(val.then) && isFunction(val.catch)
}

Vue3 還提供了 API (errorHandler)用于給用戶注冊捕獲錯誤的全局處理函數(shù),使用方法如下:

app.config.errorHandler = (err, instance, info) => {
  // 處理錯誤,例如:報告給一個服務(wù)
}

該 API (errorHandler)在 handleError 函數(shù)中實現(xiàn)

// packages/runtime-core/src/errorHandling.ts

export function handleError(
  err: unknown,
  instance: ComponentInternalInstance | null,
  type: ErrorTypes,
  throwInDev = true
) {
  const contextVNode = instance ? instance.vnode : null
  // 省略其他代碼
  if (instance) {
    // 讀取用戶配置的全局錯誤處理函數(shù)
    const appErrorHandler = instance.appContext.config.errorHandler
    if (appErrorHandler) {
      // 如果存在用戶配置的全局錯誤處理函數(shù)則放入 callWithErrorHandling 中執(zhí)行
      callWithErrorHandling(
        appErrorHandler,
        null,
        ErrorCodes.APP_ERROR_HANDLER,
        [err, exposedInstance, errorInfo]
      )
      return
    }
  }
  // 省略其他代碼
}

Vue3 會判斷用戶是否配置了全局錯誤處理函數(shù),如果配置了則會丟給內(nèi)置的同步異常處理函數(shù)執(zhí)行(callWithErrorHandling)。由于用戶配置的全局錯誤處理函數(shù)執(zhí)行是給同步異常處理函數(shù)執(zhí)行的,因此,用戶在自定義全局錯誤處理函數(shù)時,要注意兼容異步錯誤的情況,即最好在自定義全局處理函數(shù)中,加上對異步錯誤代碼的處理,因為 Vue3 內(nèi)部沒法捕獲到異步的錯誤。

如果要做前端的異常監(jiān)控,我們完全可以借助 errorHandler 函數(shù),完成前端異常的上報。

Vue3 還提供了在捕獲了后代組件傳遞的錯誤時調(diào)用的生命周期鉤子(onErrorCaptured()):

function onErrorCaptured(callback: ErrorCapturedHook): void

type ErrorCapturedHook = (
  err: unknown,
  instance: ComponentPublicInstance | null,
  info: string
) => boolean | void

該生命周期鉤子(onErrorCaptured()) 也是在 handleError 函數(shù)實現(xiàn)

// packages/runtime-core/src/errorHandling.ts

export function handleError(
  err: unknown,
  instance: ComponentInternalInstance | null,
  type: ErrorTypes,
  throwInDev = true
) {
  const contextVNode = instance ? instance.vnode : null
  if (instance) {
    // 1. 獲取父組件實例
    let cur = instance.parent
    const exposedInstance = instance.proxy
    const errorInfo = __DEV__ ? ErrorTypeStrings[type] : type
    // 2. 開啟 while 循環(huán),不斷向上遍歷,取得父組件實例
    while (cur) {
      // 3. 從父組件實例中獲取 onErrorCaptured 生命周期鉤子
      const errorCapturedHooks = cur.ec
      if (errorCapturedHooks) {
        // 4. 遍歷 onErrorCaptured 生命周期鉤子數(shù)組
        for (let i = 0; i < errorCapturedHooks.length; i++) {
          if (
            // 5. 執(zhí)行 onErrorCaptured 生命周期鉤子,
            // onErrorCaptured 返回 false 則退出 while 循環(huán),
            // 錯誤會停止向上傳遞
            errorCapturedHooks[i](err, exposedInstance, errorInfo) === false
          ) {
            return
          }
        }
      }
      cur = cur.parent
    }
  }
}

由于 Vue3 的組件可以多次注冊同一個生命周期鉤子,所以 Vue3 內(nèi)部使用了數(shù)組來存儲 onErrorCaptured 生命周期鉤子。Vue3 內(nèi)部會使用 while 循環(huán),不斷向上遍歷取得父組件實例的 onErrorCaptured 生命周期鉤子,然后遍歷執(zhí)行 onErrorCaptured 生命周期鉤子,如果 onErrorCaptured 生命周期鉤子返回 false ,則會退出 while 循環(huán),停止向上傳遞錯誤。

錯誤碼與錯誤信息

前端在與后端進行接口聯(lián)調(diào)的時候,肯定見過各種 HTTP 的狀態(tài)碼,比如 404(無法找到資源)、500(服務(wù)器內(nèi)部錯誤)等。狀態(tài)碼的好處是可以讓用戶快速地知道當(dāng)前 HTTP 請求的狀態(tài),方便用戶排查錯誤等。

因此,在 Vue 中,也定義了各種錯誤碼(狀態(tài)碼),用來區(qū)分各種類型的錯誤,方便開發(fā)者(Vue 用戶)排查錯誤。

// packages/runtime-core/src/errorHandling.ts

export const enum ErrorCodes {
  SETUP_FUNCTION,
  RENDER_FUNCTION,
  WATCH_GETTER,
  WATCH_CALLBACK,
  WATCH_CLEANUP,
  NATIVE_EVENT_HANDLER,
  COMPONENT_EVENT_HANDLER,
  VNODE_HOOK,
  DIRECTIVE_HOOK,
  TRANSITION_HOOK,
  APP_ERROR_HANDLER,
  APP_WARN_HANDLER,
  FUNCTION_REF,
  ASYNC_COMPONENT_LOADER,
  SCHEDULER
}

// 不同的狀態(tài)碼對應(yīng)不同的錯誤信息
export const ErrorTypeStrings: Record<number | string, string> = {
  // 省略其他代碼
  [ErrorCodes.SETUP_FUNCTION]: 'setup function',
  [ErrorCodes.RENDER_FUNCTION]: 'render function',
  [ErrorCodes.WATCH_GETTER]: 'watcher getter',
  [ErrorCodes.WATCH_CALLBACK]: 'watcher callback',
  [ErrorCodes.WATCH_CLEANUP]: 'watcher cleanup function',
  [ErrorCodes.NATIVE_EVENT_HANDLER]: 'native event handler',
  [ErrorCodes.COMPONENT_EVENT_HANDLER]: 'component event handler',
  [ErrorCodes.VNODE_HOOK]: 'vnode hook',
  [ErrorCodes.DIRECTIVE_HOOK]: 'directive hook',
  [ErrorCodes.TRANSITION_HOOK]: 'transition hook',
  [ErrorCodes.APP_ERROR_HANDLER]: 'app errorHandler',
  [ErrorCodes.APP_WARN_HANDLER]: 'app warnHandler',
  [ErrorCodes.FUNCTION_REF]: 'ref function',
  [ErrorCodes.ASYNC_COMPONENT_LOADER]: 'async component loader',
  [ErrorCodes.SCHEDULER]:
    'scheduler flush. This is likely a Vue internals bug. ' +
    'Please open an issue at https://new-issue.vuejs.org/?repo=vuejs/core'
}

Vue 會根據(jù)不同的錯誤碼取不同的錯誤信息輸出,方便用戶排查錯誤。

// packages/runtime-core/src/errorHandling.ts

// 省略了一些無關(guān)的代碼
function logError(
  err: unknown,
  type: ErrorTypes,
  contextVNode: VNode | null,
  throwInDev = true
) {
  if (__DEV__) {
    // 根據(jù)錯誤碼取出錯誤信息輸出
    const info = ErrorTypeStrings[type]
    warn(`Unhandled error${info ? ` during execution of ${info}` : ``}`)
  } else {
    console.error(err)
  }
}

同時為了控制生產(chǎn)環(huán)境框架的代碼體積,利用了 Tree Shaking 機制,僅在開發(fā)環(huán)境(__DEV__)輸出內(nèi)部的錯誤信息。

總結(jié)

錯誤處理是框架設(shè)計的核心要素之一,Vue3 內(nèi)部提供了兩種處理異常的函數(shù),同步異常處理函數(shù)(callWithErrorHanding)和異步異常處理函數(shù)(callWithErrorHanding),異步異常處理函數(shù)、給用戶自定義的全局錯誤處理函數(shù)、捕獲了子組件異常后調(diào)用的生命周期鉤子(onErrorCaptured)均是基于同步異常處理函數(shù)(callWithErrorHanding)實現(xiàn),而同步異常處理函數(shù)(callWithErrorHanding)本質(zhì)是對 try catch 的封裝。

Vue3 還提供了錯誤碼和對應(yīng)的錯誤信息來幫助開發(fā)者(Vue 的用戶)快速地排查錯誤。

從錯誤處理到錯誤碼和錯誤信息,可以看出 Vue 的錯誤處理做得是比較完善的。

到此這篇關(guān)于源碼剖析Vue3中如何進行錯誤處理的文章就介紹到這了,更多相關(guān)Vue3錯誤處理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 使用vite創(chuàng)建vue3之vite.config.js的配置方式

    使用vite創(chuàng)建vue3之vite.config.js的配置方式

    這篇文章主要介紹了使用vite創(chuàng)建vue3之vite.config.js的配置方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • vue登錄注冊實例詳解

    vue登錄注冊實例詳解

    在本篇內(nèi)容里小編給大家分享的是關(guān)于vue登錄注冊的相關(guān)實例內(nèi)容以及寫法分析,有需要朋友們可以學(xué)習(xí)下。
    2019-09-09
  • vue使用vuex實現(xiàn)首頁導(dǎo)航切換不同路由的方法

    vue使用vuex實現(xiàn)首頁導(dǎo)航切換不同路由的方法

    這篇文章主要介紹了vue使用vuex實現(xiàn)首頁導(dǎo)航切換不同路由的方法 ,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-05-05
  • Vue?Echarts實現(xiàn)多功能圖表繪制的示例詳解

    Vue?Echarts實現(xiàn)多功能圖表繪制的示例詳解

    作為前端人員,日常圖表、報表、地圖的接觸可謂相當(dāng)頻繁,今天小編隆重退出前端框架之VUE結(jié)合百度echart實現(xiàn)中國地圖+各種圖表的展示與使用;作為“你值得擁有”專欄階段性末篇,值得一看
    2023-02-02
  • 解決nuxt頁面中mounted、created、watch執(zhí)行兩遍的問題

    解決nuxt頁面中mounted、created、watch執(zhí)行兩遍的問題

    這篇文章主要介紹了解決nuxt頁面中mounted、created、watch執(zhí)行兩遍的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11
  • Vue 重置data的數(shù)據(jù)為初始狀態(tài)操作

    Vue 重置data的數(shù)據(jù)為初始狀態(tài)操作

    這篇文章主要介紹了Vue 重置data的數(shù)據(jù)為初始狀態(tài)操作方案,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-03-03
  • VNode虛擬節(jié)點實例簡析

    VNode虛擬節(jié)點實例簡析

    這篇文章主要介紹了VNode虛擬節(jié)點,結(jié)合實例形式分析了VNode虛擬節(jié)點的基本功能、原理與實現(xiàn)方法,需要的朋友可以參考下
    2023-06-06
  • 使用Vue開發(fā)自己的Chrome擴展程序過程詳解

    使用Vue開發(fā)自己的Chrome擴展程序過程詳解

    這篇文章主要介紹了使用Vue開發(fā)自己的Chrome擴展程序過程詳解,瀏覽器擴展程序是可以修改和增強 Web 瀏覽器功能的小程序。它們可用于各種任務(wù),例如阻止廣告,管理密碼,組織標(biāo)簽,改變網(wǎng)頁的外觀和行為等等。,需要的朋友可以參考下
    2019-06-06
  • vue中jsencrypt與base64加密解密的實用流程

    vue中jsencrypt與base64加密解密的實用流程

    vue項目里面使用到的加密和解密的方法,本文主要介紹了vue中jsencrypt與base64加密解密的實用流程,具有一定的參考價值,感興趣的可以了解一下
    2023-10-10
  • vue小圖標(biāo)favicon不顯示的解決方案

    vue小圖標(biāo)favicon不顯示的解決方案

    本篇文章主要介紹了vue小圖標(biāo)favicon不顯示的解決方案,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09

最新評論

蒙山县| 安新县| 舞阳县| 吉林省| 稻城县| 巫山县| 辛集市| 镶黄旗| 侯马市| 平湖市| 伊金霍洛旗| 府谷县| 兴义市| 石阡县| 清远市| 卫辉市| 辽源市| 冀州市| 贺兰县| 舞阳县| 清徐县| 安国市| 呼图壁县| 晋州市| 巴林左旗| 隆子县| 锡林浩特市| 延川县| 盘山县| 朝阳区| 肥城市| 沽源县| 永新县| 哈密市| 古浪县| 晋江市| 沙坪坝区| 新绛县| 南昌县| 甘孜县| 宣化县|