diff --git a/packages/runtime-core/__tests__/apiAsyncComponent.spec.ts b/packages/runtime-core/__tests__/apiAsyncComponent.spec.ts index fb989296bc1..5c3f6a6b85e 100644 --- a/packages/runtime-core/__tests__/apiAsyncComponent.spec.ts +++ b/packages/runtime-core/__tests__/apiAsyncComponent.spec.ts @@ -488,7 +488,13 @@ describe('api: defineAsyncComponent', () => { reject = _reject }) }, - retryWhen: error => error.message.match(/foo/) + onError(error, retry, fail) { + if (error.message.match(/foo/)) { + retry() + } else { + fail() + } + } }) const root = nodeOps.createElement('div') @@ -526,7 +532,13 @@ describe('api: defineAsyncComponent', () => { reject = _reject }) }, - retryWhen: error => error.message.match(/bar/) + onError(error, retry, fail) { + if (error.message.match(/bar/)) { + retry() + } else { + fail() + } + } }) const root = nodeOps.createElement('div') @@ -549,7 +561,7 @@ describe('api: defineAsyncComponent', () => { expect(serializeInner(root)).toBe('') }) - test('retry (fail w/ maxRetries)', async () => { + test('retry (fail w/ max retry attempts)', async () => { let loaderCallCount = 0 let reject: (e: Error) => void @@ -560,8 +572,13 @@ describe('api: defineAsyncComponent', () => { reject = _reject }) }, - retryWhen: error => error.message.match(/foo/), - maxRetries: 1 + onError(error, retry, fail, attempts) { + if (error.message.match(/foo/) && attempts <= 1) { + retry() + } else { + fail() + } + } }) const root = nodeOps.createElement('div') diff --git a/packages/runtime-core/src/apiAsyncComponent.ts b/packages/runtime-core/src/apiAsyncComponent.ts index bc18e542f6c..7f65f3b47b2 100644 --- a/packages/runtime-core/src/apiAsyncComponent.ts +++ b/packages/runtime-core/src/apiAsyncComponent.ts @@ -5,7 +5,7 @@ import { ComponentInternalInstance, isInSSRComponentSetup } from './component' -import { isFunction, isObject, NO } from '@vue/shared' +import { isFunction, isObject } from '@vue/shared' import { ComponentPublicInstance } from './componentProxy' import { createVNode } from './vnode' import { defineComponent } from './apiDefineComponent' @@ -27,9 +27,13 @@ export interface AsyncComponentOptions { errorComponent?: PublicAPIComponent delay?: number timeout?: number - retryWhen?: (error: Error) => any - maxRetries?: number suspensible?: boolean + onError?: ( + error: Error, + retry: () => void, + fail: () => void, + attempts: number + ) => any } export function defineAsyncComponent< @@ -45,16 +49,15 @@ export function defineAsyncComponent< errorComponent: errorComponent, delay = 200, timeout, // undefined = never times out - retryWhen = NO, - maxRetries = 3, - suspensible = true + suspensible = true, + onError: userOnError } = source let pendingRequest: Promise | null = null let resolvedComp: Component | undefined let retries = 0 - const retry = (error?: unknown) => { + const retry = () => { retries++ pendingRequest = null return load() @@ -67,8 +70,12 @@ export function defineAsyncComponent< (thisRequest = pendingRequest = loader() .catch(err => { err = err instanceof Error ? err : new Error(String(err)) - if (retryWhen(err) && retries < maxRetries) { - return retry(err) + if (userOnError) { + return new Promise((resolve, reject) => { + const userRetry = () => resolve(retry()) + const userFail = () => reject(err) + userOnError(err, userRetry, userFail, retries + 1) + }) } else { throw err }