2
0

errorHandling.ts 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. import { VNode } from './vnode'
  2. import { ComponentInstance, LifecycleHooks } from './component'
  3. import { warn, pushWarningContext, popWarningContext } from './warning'
  4. // contexts where user provided function may be executed, in addition to
  5. // lifecycle hooks.
  6. export const enum ErrorTypes {
  7. SETUP_FUNCTION = 1,
  8. RENDER_FUNCTION,
  9. WATCH_GETTER,
  10. WATCH_CALLBACK,
  11. WATCH_CLEANUP,
  12. NATIVE_EVENT_HANDLER,
  13. COMPONENT_EVENT_HANDLER,
  14. DIRECTIVE_HOOK,
  15. SCHEDULER
  16. }
  17. export const ErrorTypeStrings: Record<number | string, string> = {
  18. [LifecycleHooks.BEFORE_CREATE]: 'beforeCreate hook',
  19. [LifecycleHooks.CREATED]: 'created hook',
  20. [LifecycleHooks.BEFORE_MOUNT]: 'beforeMount hook',
  21. [LifecycleHooks.MOUNTED]: 'mounted hook',
  22. [LifecycleHooks.BEFORE_UPDATE]: 'beforeUpdate hook',
  23. [LifecycleHooks.UPDATED]: 'updated',
  24. [LifecycleHooks.BEFORE_UNMOUNT]: 'beforeUnmount hook',
  25. [LifecycleHooks.UNMOUNTED]: 'unmounted hook',
  26. [LifecycleHooks.ACTIVATED]: 'activated hook',
  27. [LifecycleHooks.DEACTIVATED]: 'deactivated hook',
  28. [LifecycleHooks.ERROR_CAPTURED]: 'errorCaptured hook',
  29. [LifecycleHooks.RENDER_TRACKED]: 'renderTracked hook',
  30. [LifecycleHooks.RENDER_TRIGGERED]: 'renderTriggered hook',
  31. [ErrorTypes.SETUP_FUNCTION]: 'setup function',
  32. [ErrorTypes.RENDER_FUNCTION]: 'render function',
  33. [ErrorTypes.WATCH_GETTER]: 'watcher getter',
  34. [ErrorTypes.WATCH_CALLBACK]: 'watcher callback',
  35. [ErrorTypes.WATCH_CLEANUP]: 'watcher cleanup function',
  36. [ErrorTypes.NATIVE_EVENT_HANDLER]: 'native event handler',
  37. [ErrorTypes.COMPONENT_EVENT_HANDLER]: 'component event handler',
  38. [ErrorTypes.DIRECTIVE_HOOK]: 'directive hook',
  39. [ErrorTypes.SCHEDULER]:
  40. 'scheduler flush. This may be a Vue internals bug. ' +
  41. 'Please open an issue at https://new-issue.vuejs.org/?repo=vuejs/vue'
  42. }
  43. type AllErrorTypes = LifecycleHooks | ErrorTypes
  44. export function callWithErrorHandling(
  45. fn: Function,
  46. instance: ComponentInstance | null,
  47. type: AllErrorTypes,
  48. args?: any[]
  49. ) {
  50. let res: any
  51. try {
  52. res = args ? fn(...args) : fn()
  53. } catch (err) {
  54. handleError(err, instance, type)
  55. }
  56. return res
  57. }
  58. export function callWithAsyncErrorHandling(
  59. fn: Function,
  60. instance: ComponentInstance | null,
  61. type: AllErrorTypes,
  62. args?: any[]
  63. ) {
  64. const res = callWithErrorHandling(fn, instance, type, args)
  65. if (res != null && !res._isVue && typeof res.then === 'function') {
  66. ;(res as Promise<any>).catch(err => {
  67. handleError(err, instance, type)
  68. })
  69. }
  70. return res
  71. }
  72. export function handleError(
  73. err: Error,
  74. instance: ComponentInstance | null,
  75. type: AllErrorTypes
  76. ) {
  77. const contextVNode = instance ? instance.vnode : null
  78. let cur: ComponentInstance | null = instance && instance.parent
  79. while (cur) {
  80. const errorCapturedHooks = cur.ec
  81. if (errorCapturedHooks !== null) {
  82. for (let i = 0; i < errorCapturedHooks.length; i++) {
  83. if (
  84. errorCapturedHooks[i](
  85. err,
  86. instance && instance.renderProxy,
  87. // in production the hook receives only the error code
  88. __DEV__ ? ErrorTypeStrings[type] : type
  89. )
  90. ) {
  91. return
  92. }
  93. }
  94. }
  95. cur = cur.parent
  96. }
  97. logError(err, type, contextVNode)
  98. }
  99. function logError(err: Error, type: AllErrorTypes, contextVNode: VNode | null) {
  100. if (__DEV__) {
  101. const info = ErrorTypeStrings[type]
  102. if (contextVNode) {
  103. pushWarningContext(contextVNode)
  104. }
  105. warn(`Unhandled error${info ? ` during execution of ${info}` : ``}`)
  106. console.error(err)
  107. if (contextVNode) {
  108. popWarningContext()
  109. }
  110. } else {
  111. throw err
  112. }
  113. }