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