mirror of
https://gitee.com/vuejs/vue.git
synced 2024-12-05 05:27:59 +08:00
async component improvements
This commit is contained in:
parent
354c2f4922
commit
4e980976ea
@ -1,62 +1,101 @@
|
||||
/* @flow */
|
||||
|
||||
// () => ({
|
||||
// component: import('./xxx.vue'),
|
||||
// delay: 200,
|
||||
// loading: LoadingComponent,
|
||||
// error: ErrorComponent
|
||||
// })
|
||||
|
||||
import {
|
||||
warn,
|
||||
isObject
|
||||
once,
|
||||
isDef,
|
||||
isUndef,
|
||||
isTrue,
|
||||
isObject,
|
||||
isFunction
|
||||
} from 'core/util/index'
|
||||
|
||||
function ensureCtor (comp, base) {
|
||||
return isObject(comp)
|
||||
? base.extend(comp)
|
||||
: comp
|
||||
}
|
||||
|
||||
export function resolveAsyncComponent (
|
||||
factory: Function,
|
||||
baseCtor: Class<Component>,
|
||||
context: Component
|
||||
): Class<Component> | void {
|
||||
if (factory.resolved) {
|
||||
if (isTrue(factory.error) && isDef(factory.errorComp)) {
|
||||
return factory.errorComp
|
||||
}
|
||||
|
||||
if (isDef(factory.resolved)) {
|
||||
return factory.resolved
|
||||
}
|
||||
|
||||
const cb = () => context.$forceUpdate()
|
||||
if (factory.requested) {
|
||||
// pool callbacks
|
||||
factory.pendingCallbacks.push(cb)
|
||||
if (isTrue(factory.loading) && isDef(factory.loadingComp)) {
|
||||
return factory.loadingComp
|
||||
}
|
||||
|
||||
if (isDef(factory.contexts)) {
|
||||
// already pending
|
||||
factory.contexts.push(context)
|
||||
} else {
|
||||
factory.requested = true
|
||||
const cbs = factory.pendingCallbacks = [cb]
|
||||
const contexts = factory.contexts = [context]
|
||||
let sync = true
|
||||
|
||||
const resolve = (res: Object | Class<Component>) => {
|
||||
if (isObject(res)) {
|
||||
res = baseCtor.extend(res)
|
||||
}
|
||||
// cache resolved
|
||||
factory.resolved = res
|
||||
// invoke callbacks only if this is not a synchronous resolve
|
||||
// (async resolves are shimmed as synchronous during SSR)
|
||||
if (!sync) {
|
||||
for (let i = 0, l = cbs.length; i < l; i++) {
|
||||
cbs[i](res)
|
||||
}
|
||||
const forceRender = () => {
|
||||
for (let i = 0, l = contexts.length; i < l; i++) {
|
||||
contexts[i].$forceUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
const reject = reason => {
|
||||
const resolve = once((res: Object | Class<Component>) => {
|
||||
// cache resolved
|
||||
factory.resolved = ensureCtor(res, baseCtor)
|
||||
// invoke callbacks only if this is not a synchronous resolve
|
||||
// (async resolves are shimmed as synchronous during SSR)
|
||||
if (!sync) {
|
||||
forceRender()
|
||||
}
|
||||
})
|
||||
|
||||
const reject = once(reason => {
|
||||
process.env.NODE_ENV !== 'production' && warn(
|
||||
`Failed to resolve async component: ${String(factory)}` +
|
||||
(reason ? `\nReason: ${reason}` : '')
|
||||
)
|
||||
}
|
||||
if (isDef(factory.errorComp)) {
|
||||
factory.error = true
|
||||
forceRender()
|
||||
}
|
||||
})
|
||||
|
||||
const res = factory(resolve, reject)
|
||||
|
||||
// handle promise
|
||||
if (res && typeof res.then === 'function' && !factory.resolved) {
|
||||
res.then(resolve, reject)
|
||||
if (isObject(res)) {
|
||||
if (isFunction(res.then)) {
|
||||
// () => Promise
|
||||
if (isUndef(factory.resolved)) {
|
||||
res.then(resolve, reject)
|
||||
}
|
||||
} else if (isDef(res.component) && isFunction(res.component.then)) {
|
||||
if (isDef(res.error)) {
|
||||
factory.errorComp = ensureCtor(res.error, baseCtor)
|
||||
}
|
||||
|
||||
if (isDef(res.loading)) {
|
||||
factory.loadingComp = ensureCtor(res.loading, baseCtor)
|
||||
setTimeout(() => {
|
||||
if (isUndef(factory.resolved) && isUndef(factory.error)) {
|
||||
factory.loading = true
|
||||
forceRender()
|
||||
}
|
||||
}, res.delay || 200)
|
||||
}
|
||||
|
||||
if (isDef(res.timeout)) {
|
||||
setTimeout(reject, res.timeout)
|
||||
}
|
||||
|
||||
res.component.then(resolve, reject)
|
||||
}
|
||||
}
|
||||
|
||||
sync = false
|
||||
|
@ -14,6 +14,10 @@ export function isTrue (v: any): boolean {
|
||||
return v === true
|
||||
}
|
||||
|
||||
export function isFunction (v: any): boolean {
|
||||
return typeof v === 'function'
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a value to a string that is actually rendered.
|
||||
*/
|
||||
@ -250,10 +254,10 @@ export function looseIndexOf (arr: Array<mixed>, val: mixed): number {
|
||||
*/
|
||||
export function once (fn: Function): Function {
|
||||
let called = false
|
||||
return () => {
|
||||
return function () {
|
||||
if (!called) {
|
||||
called = true
|
||||
fn()
|
||||
fn.apply(this, arguments)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user