feat(asyncComponent): add onError
option for defineAsyncComponent
BREAKING CHANGE: `retryWhen` and `maxRetries` options for `defineAsyncComponent` has been replaced by the more flexible `onError` option, per https://github.com/vuejs/rfcs/pull/148
This commit is contained in:
parent
f87d6b501e
commit
e804463492
@ -488,7 +488,13 @@ describe('api: defineAsyncComponent', () => {
|
|||||||
reject = _reject
|
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')
|
const root = nodeOps.createElement('div')
|
||||||
@ -526,7 +532,13 @@ describe('api: defineAsyncComponent', () => {
|
|||||||
reject = _reject
|
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')
|
const root = nodeOps.createElement('div')
|
||||||
@ -549,7 +561,7 @@ describe('api: defineAsyncComponent', () => {
|
|||||||
expect(serializeInner(root)).toBe('<!---->')
|
expect(serializeInner(root)).toBe('<!---->')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('retry (fail w/ maxRetries)', async () => {
|
test('retry (fail w/ max retry attempts)', async () => {
|
||||||
let loaderCallCount = 0
|
let loaderCallCount = 0
|
||||||
let reject: (e: Error) => void
|
let reject: (e: Error) => void
|
||||||
|
|
||||||
@ -560,8 +572,13 @@ describe('api: defineAsyncComponent', () => {
|
|||||||
reject = _reject
|
reject = _reject
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
retryWhen: error => error.message.match(/foo/),
|
onError(error, retry, fail, attempts) {
|
||||||
maxRetries: 1
|
if (error.message.match(/foo/) && attempts <= 1) {
|
||||||
|
retry()
|
||||||
|
} else {
|
||||||
|
fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const root = nodeOps.createElement('div')
|
const root = nodeOps.createElement('div')
|
||||||
|
@ -5,7 +5,7 @@ import {
|
|||||||
ComponentInternalInstance,
|
ComponentInternalInstance,
|
||||||
isInSSRComponentSetup
|
isInSSRComponentSetup
|
||||||
} from './component'
|
} from './component'
|
||||||
import { isFunction, isObject, NO } from '@vue/shared'
|
import { isFunction, isObject } from '@vue/shared'
|
||||||
import { ComponentPublicInstance } from './componentProxy'
|
import { ComponentPublicInstance } from './componentProxy'
|
||||||
import { createVNode } from './vnode'
|
import { createVNode } from './vnode'
|
||||||
import { defineComponent } from './apiDefineComponent'
|
import { defineComponent } from './apiDefineComponent'
|
||||||
@ -27,9 +27,13 @@ export interface AsyncComponentOptions<T = any> {
|
|||||||
errorComponent?: PublicAPIComponent
|
errorComponent?: PublicAPIComponent
|
||||||
delay?: number
|
delay?: number
|
||||||
timeout?: number
|
timeout?: number
|
||||||
retryWhen?: (error: Error) => any
|
|
||||||
maxRetries?: number
|
|
||||||
suspensible?: boolean
|
suspensible?: boolean
|
||||||
|
onError?: (
|
||||||
|
error: Error,
|
||||||
|
retry: () => void,
|
||||||
|
fail: () => void,
|
||||||
|
attempts: number
|
||||||
|
) => any
|
||||||
}
|
}
|
||||||
|
|
||||||
export function defineAsyncComponent<
|
export function defineAsyncComponent<
|
||||||
@ -45,16 +49,15 @@ export function defineAsyncComponent<
|
|||||||
errorComponent: errorComponent,
|
errorComponent: errorComponent,
|
||||||
delay = 200,
|
delay = 200,
|
||||||
timeout, // undefined = never times out
|
timeout, // undefined = never times out
|
||||||
retryWhen = NO,
|
suspensible = true,
|
||||||
maxRetries = 3,
|
onError: userOnError
|
||||||
suspensible = true
|
|
||||||
} = source
|
} = source
|
||||||
|
|
||||||
let pendingRequest: Promise<Component> | null = null
|
let pendingRequest: Promise<Component> | null = null
|
||||||
let resolvedComp: Component | undefined
|
let resolvedComp: Component | undefined
|
||||||
|
|
||||||
let retries = 0
|
let retries = 0
|
||||||
const retry = (error?: unknown) => {
|
const retry = () => {
|
||||||
retries++
|
retries++
|
||||||
pendingRequest = null
|
pendingRequest = null
|
||||||
return load()
|
return load()
|
||||||
@ -67,8 +70,12 @@ export function defineAsyncComponent<
|
|||||||
(thisRequest = pendingRequest = loader()
|
(thisRequest = pendingRequest = loader()
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
err = err instanceof Error ? err : new Error(String(err))
|
err = err instanceof Error ? err : new Error(String(err))
|
||||||
if (retryWhen(err) && retries < maxRetries) {
|
if (userOnError) {
|
||||||
return retry(err)
|
return new Promise((resolve, reject) => {
|
||||||
|
const userRetry = () => resolve(retry())
|
||||||
|
const userFail = () => reject(err)
|
||||||
|
userOnError(err, userRetry, userFail, retries + 1)
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
throw err
|
throw err
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user