]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
feat: error handling in scheduler
authorEvan You <yyx990803@gmail.com>
Fri, 30 Aug 2019 19:15:23 +0000 (15:15 -0400)
committerEvan You <yyx990803@gmail.com>
Fri, 30 Aug 2019 19:15:23 +0000 (15:15 -0400)
packages/runtime-core/src/apiWatch.ts
packages/runtime-core/src/component.ts
packages/runtime-core/src/errorHandling.ts
packages/runtime-core/src/scheduler.ts
packages/runtime-dom/src/modules/events.ts

index 94f3d69d335915ee924463c94b77fab2fbe15656..6d092b2a4dd47919f7b94368b6d77f3cbf141aaa 100644 (file)
@@ -10,7 +10,7 @@ import { EMPTY_OBJ, isObject, isArray, isFunction } from '@vue/shared'
 import { recordEffect } from './apiReactivity'
 import { getCurrentInstance } from './component'
 import {
-  UserExecutionContexts,
+  ErrorTypes,
   callWithErrorHandling,
   callWithAsyncErrorHandling
 } from './errorHandling'
@@ -92,22 +92,14 @@ function doWatch(
         s =>
           isRef(s)
             ? s.value
-            : callWithErrorHandling(
-                s,
-                instance,
-                UserExecutionContexts.WATCH_GETTER
-              )
+            : callWithErrorHandling(s, instance, ErrorTypes.WATCH_GETTER)
       )
   } else if (isRef(source)) {
     getter = () => source.value
   } else if (cb) {
     // getter with cb
     getter = () =>
-      callWithErrorHandling(
-        source,
-        instance,
-        UserExecutionContexts.WATCH_GETTER
-      )
+      callWithErrorHandling(source, instance, ErrorTypes.WATCH_GETTER)
   } else {
     // no cb -> simple effect
     getter = () => {
@@ -117,7 +109,7 @@ function doWatch(
       return callWithErrorHandling(
         source,
         instance,
-        UserExecutionContexts.WATCH_CALLBACK,
+        ErrorTypes.WATCH_CALLBACK,
         [registerCleanup]
       )
     }
@@ -132,7 +124,7 @@ function doWatch(
   const registerCleanup: CleanupRegistrator = (fn: () => void) => {
     // TODO wrap the cleanup fn for error handling
     cleanup = runner.onStop = () => {
-      callWithErrorHandling(fn, instance, UserExecutionContexts.WATCH_CLEANUP)
+      callWithErrorHandling(fn, instance, ErrorTypes.WATCH_CLEANUP)
     }
   }
 
@@ -145,12 +137,11 @@ function doWatch(
           if (cleanup) {
             cleanup()
           }
-          callWithAsyncErrorHandling(
-            cb,
-            instance,
-            UserExecutionContexts.WATCH_CALLBACK,
-            [newValue, oldValue, registerCleanup]
-          )
+          callWithAsyncErrorHandling(cb, instance, ErrorTypes.WATCH_CALLBACK, [
+            newValue,
+            oldValue,
+            registerCleanup
+          ])
           oldValue = newValue
         }
       }
index a7292cf28c10754402bd1d57e8d1b9fab49f1b12..82242d695a29c6cf52919caa55bff278d99f0df2 100644 (file)
@@ -8,7 +8,7 @@ import { PatchFlags } from './patchFlags'
 import { ShapeFlags } from './shapeFlags'
 import { warn } from './warning'
 import {
-  UserExecutionContexts,
+  ErrorTypes,
   handleError,
   callWithErrorHandling,
   callWithAsyncErrorHandling
@@ -238,7 +238,7 @@ export function createComponentInstance(
             callWithAsyncErrorHandling(
               handler[i],
               instance,
-              UserExecutionContexts.COMPONENT_EVENT_HANDLER,
+              ErrorTypes.COMPONENT_EVENT_HANDLER,
               args
             )
           }
@@ -246,7 +246,7 @@ export function createComponentInstance(
           callWithAsyncErrorHandling(
             handler,
             instance,
-            UserExecutionContexts.COMPONENT_EVENT_HANDLER,
+            ErrorTypes.COMPONENT_EVENT_HANDLER,
             args
           )
         }
@@ -287,7 +287,7 @@ export function setupStatefulComponent(instance: ComponentInstance) {
     const setupResult = callWithErrorHandling(
       setup,
       instance,
-      UserExecutionContexts.SETUP_FUNCTION,
+      ErrorTypes.SETUP_FUNCTION,
       [propsProxy, setupContext]
     )
     currentInstance = null
@@ -382,7 +382,7 @@ export function renderComponentRoot(instance: ComponentInstance): VNode {
       )
     }
   } catch (err) {
-    handleError(err, instance, UserExecutionContexts.RENDER_FUNCTION)
+    handleError(err, instance, ErrorTypes.RENDER_FUNCTION)
     return createVNode(Empty)
   }
 }
index cb38ad8508eed2af52c3823b7ddfa9d41f7c2db5..d868c0018b05b2fbf8e46e5d2f8646fd7a45b089 100644 (file)
@@ -4,7 +4,7 @@ import { warn, pushWarningContext, popWarningContext } from './warning'
 
 // contexts where user provided function may be executed, in addition to
 // lifecycle hooks.
-export const enum UserExecutionContexts {
+export const enum ErrorTypes {
   SETUP_FUNCTION = 1,
   RENDER_FUNCTION,
   WATCH_GETTER,
@@ -29,24 +29,24 @@ export const ErrorTypeStrings: Record<number | string, string> = {
   [LifecycleHooks.ERROR_CAPTURED]: 'errorCaptured hook',
   [LifecycleHooks.RENDER_TRACKED]: 'renderTracked hook',
   [LifecycleHooks.RENDER_TRIGGERED]: 'renderTriggered hook',
-  [UserExecutionContexts.SETUP_FUNCTION]: 'setup function',
-  [UserExecutionContexts.RENDER_FUNCTION]: 'render function',
-  [UserExecutionContexts.WATCH_GETTER]: 'watcher getter',
-  [UserExecutionContexts.WATCH_CALLBACK]: 'watcher callback',
-  [UserExecutionContexts.WATCH_CLEANUP]: 'watcher cleanup function',
-  [UserExecutionContexts.NATIVE_EVENT_HANDLER]: 'native event handler',
-  [UserExecutionContexts.COMPONENT_EVENT_HANDLER]: 'component event handler',
-  [UserExecutionContexts.SCHEDULER]:
+  [ErrorTypes.SETUP_FUNCTION]: 'setup function',
+  [ErrorTypes.RENDER_FUNCTION]: 'render function',
+  [ErrorTypes.WATCH_GETTER]: 'watcher getter',
+  [ErrorTypes.WATCH_CALLBACK]: 'watcher callback',
+  [ErrorTypes.WATCH_CLEANUP]: 'watcher cleanup function',
+  [ErrorTypes.NATIVE_EVENT_HANDLER]: 'native event handler',
+  [ErrorTypes.COMPONENT_EVENT_HANDLER]: 'component event handler',
+  [ErrorTypes.SCHEDULER]:
     'scheduler flush. This may be a Vue internals bug. ' +
     'Please open an issue at https://new-issue.vuejs.org/?repo=vuejs/vue'
 }
 
-type ErrorTypes = LifecycleHooks | UserExecutionContexts
+type AllErrorTypes = LifecycleHooks | ErrorTypes
 
 export function callWithErrorHandling(
   fn: Function,
   instance: ComponentInstance | null,
-  type: ErrorTypes,
+  type: AllErrorTypes,
   args?: any[]
 ) {
   let res: any
@@ -61,7 +61,7 @@ export function callWithErrorHandling(
 export function callWithAsyncErrorHandling(
   fn: Function,
   instance: ComponentInstance | null,
-  type: ErrorTypes,
+  type: AllErrorTypes,
   args?: any[]
 ) {
   const res = callWithErrorHandling(fn, instance, type, args)
@@ -76,7 +76,7 @@ export function callWithAsyncErrorHandling(
 export function handleError(
   err: Error,
   instance: ComponentInstance | null,
-  type: ErrorTypes
+  type: AllErrorTypes
 ) {
   const contextVNode = instance ? instance.vnode : null
   let cur: ComponentInstance | null = instance && instance.parent
@@ -100,7 +100,7 @@ export function handleError(
   logError(err, type, contextVNode)
 }
 
-function logError(err: Error, type: ErrorTypes, contextVNode: VNode | null) {
+function logError(err: Error, type: AllErrorTypes, contextVNode: VNode | null) {
   if (__DEV__) {
     const info = ErrorTypeStrings[type]
     if (contextVNode) {
index a81ecdfff3da38d1cd170b29c1d38b4c618ecd62..6f8ccaa9175954c6cc8e1f0716de6599ebea8e56 100644 (file)
@@ -1,3 +1,5 @@
+import { handleError, ErrorTypes } from './errorHandling'
+
 const queue: Function[] = []
 const postFlushCbs: Function[] = []
 const p = Promise.resolve()
@@ -8,31 +10,23 @@ export function nextTick(fn?: () => void): Promise<void> {
   return fn ? p.then(fn) : p
 }
 
-type ErrorHandler = (err: Error) => void
-
-export function queueJob(job: () => void, onError?: ErrorHandler) {
+export function queueJob(job: () => void) {
   if (queue.indexOf(job) === -1) {
     queue.push(job)
-    queueFlush(onError)
+    if (!isFlushing) {
+      nextTick(flushJobs)
+    }
   }
 }
 
-export function queuePostFlushCb(
-  cb: Function | Function[],
-  onError?: ErrorHandler
-) {
+export function queuePostFlushCb(cb: Function | Function[]) {
   if (Array.isArray(cb)) {
     postFlushCbs.push.apply(postFlushCbs, cb)
   } else {
     postFlushCbs.push(cb)
   }
-  queueFlush(onError)
-}
-
-function queueFlush(onError?: ErrorHandler) {
   if (!isFlushing) {
-    const p = nextTick(flushJobs)
-    if (onError) p.catch(onError)
+    nextTick(flushJobs)
   }
 }
 
@@ -75,7 +69,11 @@ function flushJobs(seenJobs?: JobCountMap) {
         }
       }
     }
-    job()
+    try {
+      job()
+    } catch (err) {
+      handleError(err, null, ErrorTypes.SCHEDULER)
+    }
   }
   flushPostFlushCbs()
   isFlushing = false
index 8793ad948dc83dc7eeaea1419c94ad818f8f7fce..d6663fd5373871832219cedca64677b2e33cb539 100644 (file)
@@ -3,7 +3,7 @@ import {
   ComponentInstance,
   callWithAsyncErrorHandling
 } from '@vue/runtime-core'
-import { UserExecutionContexts } from 'packages/runtime-core/src/errorHandling'
+import { ErrorTypes } from 'packages/runtime-core/src/errorHandling'
 
 interface Invoker extends Function {
   value: EventValue
@@ -77,7 +77,7 @@ function createInvoker(value: any, instance: ComponentInstance | null) {
           callWithAsyncErrorHandling(
             value[i],
             instance,
-            UserExecutionContexts.NATIVE_EVENT_HANDLER,
+            ErrorTypes.NATIVE_EVENT_HANDLER,
             args
           )
         }
@@ -85,7 +85,7 @@ function createInvoker(value: any, instance: ComponentInstance | null) {
         callWithAsyncErrorHandling(
           value,
           instance,
-          UserExecutionContexts.NATIVE_EVENT_HANDLER,
+          ErrorTypes.NATIVE_EVENT_HANDLER,
           args
         )
       }