diff --git a/packages/runtime-core/__tests__/scheduler.spec.ts b/packages/runtime-core/__tests__/scheduler.spec.ts index 9e0e104329a..cbd349fe812 100644 --- a/packages/runtime-core/__tests__/scheduler.spec.ts +++ b/packages/runtime-core/__tests__/scheduler.spec.ts @@ -294,4 +294,19 @@ describe('scheduler', () => { await nextTick() expect(calls).toEqual(['cb1', 'cb2']) }) + + test('nextTick should capture scheduler flush errors', async () => { + const err = new Error('test') + queueJob(() => { + throw err + }) + try { + await nextTick() + } catch (e) { + expect(e).toBe(err) + } + expect( + `Unhandled error during execution of scheduler flush` + ).toHaveBeenWarned() + }) }) diff --git a/packages/runtime-core/src/scheduler.ts b/packages/runtime-core/src/scheduler.ts index 8a775b39341..33743dce639 100644 --- a/packages/runtime-core/src/scheduler.ts +++ b/packages/runtime-core/src/scheduler.ts @@ -8,7 +8,8 @@ export interface Job { const queue: (Job | null)[] = [] const postFlushCbs: Function[] = [] -const p = Promise.resolve() +const resolvedPromise: Promise = Promise.resolve() +let currentFlushPromise: Promise | null = null let isFlushing = false let isFlushPending = false @@ -20,6 +21,7 @@ const RECURSION_LIMIT = 100 type CountMap = Map export function nextTick(fn?: () => void): Promise { + const p = currentFlushPromise || resolvedPromise return fn ? p.then(fn) : p } @@ -57,7 +59,7 @@ export function queuePostFlushCb(cb: Function | Function[]) { function queueFlush() { if (!isFlushing && !isFlushPending) { isFlushPending = true - nextTick(flushJobs) + currentFlushPromise = resolvedPromise.then(flushJobs) } } @@ -117,6 +119,7 @@ function flushJobs(seen?: CountMap) { flushPostFlushCbs(seen) isFlushing = false + currentFlushPromise = null // some postFlushCb queued jobs! // keep flushing until it drains. if (queue.length || postFlushCbs.length) {