errorHandling.ts 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. import { ComponentInstance } from './component'
  2. import { warn, pushWarningContext, popWarningContext } from './warning'
  3. import { VNode } from './vdom'
  4. import { VNodeFlags } from './flags'
  5. export const enum ErrorTypes {
  6. BEFORE_CREATE = 1,
  7. CREATED,
  8. BEFORE_MOUNT,
  9. MOUNTED,
  10. BEFORE_UPDATE,
  11. UPDATED,
  12. BEFORE_UNMOUNT,
  13. UNMOUNTED,
  14. ACTIVATED,
  15. DEACTIVATED,
  16. ERROR_CAPTURED,
  17. RENDER,
  18. RENDER_TRACKED,
  19. RENDER_TRIGGERED,
  20. WATCH_CALLBACK,
  21. NATIVE_EVENT_HANDLER,
  22. COMPONENT_EVENT_HANDLER,
  23. SCHEDULER
  24. }
  25. const ErrorTypeStrings: Record<number, string> = {
  26. [ErrorTypes.BEFORE_CREATE]: 'in beforeCreate lifecycle hook',
  27. [ErrorTypes.CREATED]: 'in created lifecycle hook',
  28. [ErrorTypes.BEFORE_MOUNT]: 'in beforeMount lifecycle hook',
  29. [ErrorTypes.MOUNTED]: 'in mounted lifecycle hook',
  30. [ErrorTypes.BEFORE_UPDATE]: 'in beforeUpdate lifecycle hook',
  31. [ErrorTypes.UPDATED]: 'in updated lifecycle hook',
  32. [ErrorTypes.BEFORE_UNMOUNT]: 'in beforeUnmount lifecycle hook',
  33. [ErrorTypes.UNMOUNTED]: 'in unmounted lifecycle hook',
  34. [ErrorTypes.ACTIVATED]: 'in activated lifecycle hook',
  35. [ErrorTypes.DEACTIVATED]: 'in deactivated lifecycle hook',
  36. [ErrorTypes.ERROR_CAPTURED]: 'in errorCaptured lifecycle hook',
  37. [ErrorTypes.RENDER]: 'in render function',
  38. [ErrorTypes.RENDER_TRACKED]: 'in renderTracked debug hook',
  39. [ErrorTypes.RENDER_TRIGGERED]: 'in renderTriggered debug hook',
  40. [ErrorTypes.WATCH_CALLBACK]: 'in watcher callback',
  41. [ErrorTypes.NATIVE_EVENT_HANDLER]: 'in native event handler',
  42. [ErrorTypes.COMPONENT_EVENT_HANDLER]: 'in component event handler',
  43. [ErrorTypes.SCHEDULER]:
  44. 'when flushing updates. This may be a Vue internals bug.'
  45. }
  46. export function callLifecycleHookWithHandler(
  47. hook: Function,
  48. instanceProxy: ComponentInstance,
  49. type: ErrorTypes,
  50. arg?: any
  51. ) {
  52. try {
  53. const res = hook.call(instanceProxy, arg)
  54. if (res && typeof res.then === 'function') {
  55. ;(res as Promise<any>).catch(err => {
  56. handleError(err, instanceProxy._self, type)
  57. })
  58. }
  59. } catch (err) {
  60. handleError(err, instanceProxy._self, type)
  61. }
  62. }
  63. export function handleError(
  64. err: Error,
  65. instance: ComponentInstance | VNode | null,
  66. type: ErrorTypes
  67. ) {
  68. const isFunctional = instance && (instance as VNode)._isVNode
  69. const contextVNode =
  70. instance &&
  71. ((isFunctional
  72. ? instance
  73. : (instance as ComponentInstance).$parentVNode) as VNode | null)
  74. let cur: ComponentInstance | null = null
  75. if (isFunctional) {
  76. let vnode = instance as VNode | null
  77. while (vnode && !(vnode.flags & VNodeFlags.COMPONENT_STATEFUL)) {
  78. vnode = vnode.contextVNode
  79. }
  80. if (vnode) {
  81. cur = vnode.children as ComponentInstance
  82. }
  83. } else if (instance) {
  84. cur = (instance as ComponentInstance).$parent
  85. }
  86. while (cur) {
  87. cur = cur._self
  88. const handler = cur.errorCaptured
  89. if (handler) {
  90. try {
  91. const captured = handler.call(
  92. cur,
  93. err,
  94. type,
  95. isFunctional ? null : instance
  96. )
  97. if (captured) return
  98. } catch (err2) {
  99. logError(err2, ErrorTypes.ERROR_CAPTURED, contextVNode)
  100. }
  101. }
  102. cur = cur.$parent
  103. }
  104. logError(err, type, contextVNode)
  105. }
  106. function logError(err: Error, type: ErrorTypes, contextVNode: VNode | null) {
  107. if (__DEV__) {
  108. const info = ErrorTypeStrings[type]
  109. if (contextVNode) {
  110. pushWarningContext(contextVNode)
  111. }
  112. warn(`Unhandled error${info ? ` ${info}` : ``}`)
  113. if (contextVNode) {
  114. popWarningContext()
  115. }
  116. console.error(err)
  117. } else {
  118. throw err
  119. }
  120. }