| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- /* @flow */
- import {
- warn,
- once,
- isDef,
- isUndef,
- isTrue,
- isObject,
- hasSymbol,
- isPromise,
- remove
- } from 'core/util/index'
- import { createEmptyVNode } from 'core/vdom/vnode'
- import { currentRenderingInstance } from 'core/instance/render'
- function ensureCtor (comp: any, base) {
- if (
- comp.__esModule ||
- (hasSymbol && comp[Symbol.toStringTag] === 'Module')
- ) {
- comp = comp.default
- }
- return isObject(comp)
- ? base.extend(comp)
- : comp
- }
- export function createAsyncPlaceholder (
- factory: Function,
- data: ?VNodeData,
- context: Component,
- children: ?Array<VNode>,
- tag: ?string
- ): VNode {
- const node = createEmptyVNode()
- node.asyncFactory = factory
- node.asyncMeta = { data, context, children, tag }
- return node
- }
- export function resolveAsyncComponent (
- factory: Function,
- baseCtor: Class<Component>
- ): Class<Component> | void {
- if (isTrue(factory.error) && isDef(factory.errorComp)) {
- return factory.errorComp
- }
- if (isDef(factory.resolved)) {
- return factory.resolved
- }
- const owner = currentRenderingInstance
- if (owner && isDef(factory.owners) && factory.owners.indexOf(owner) === -1) {
- // already pending
- factory.owners.push(owner)
- }
- if (isTrue(factory.loading) && isDef(factory.loadingComp)) {
- return factory.loadingComp
- }
- if (owner && !isDef(factory.owners)) {
- const owners = factory.owners = [owner]
- let sync = true
- let timerLoading = null
- let timerTimeout = null
- ;(owner: any).$on('hook:destroyed', () => remove(owners, owner))
- const forceRender = (renderCompleted: boolean) => {
- for (let i = 0, l = owners.length; i < l; i++) {
- (owners[i]: any).$forceUpdate()
- }
- if (renderCompleted) {
- owners.length = 0
- if (timerLoading !== null) {
- clearTimeout(timerLoading)
- timerLoading = null
- }
- if (timerTimeout !== null) {
- clearTimeout(timerTimeout)
- timerTimeout = null
- }
- }
- }
- 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(true)
- } else {
- owners.length = 0
- }
- })
- 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(true)
- }
- })
- const res = factory(resolve, reject)
- if (isObject(res)) {
- if (isPromise(res)) {
- // () => Promise
- if (isUndef(factory.resolved)) {
- res.then(resolve, reject)
- }
- } else if (isPromise(res.component)) {
- res.component.then(resolve, reject)
- if (isDef(res.error)) {
- factory.errorComp = ensureCtor(res.error, baseCtor)
- }
- if (isDef(res.loading)) {
- factory.loadingComp = ensureCtor(res.loading, baseCtor)
- if (res.delay === 0) {
- factory.loading = true
- } else {
- timerLoading = setTimeout(() => {
- timerLoading = null
- if (isUndef(factory.resolved) && isUndef(factory.error)) {
- factory.loading = true
- forceRender(false)
- }
- }, res.delay || 200)
- }
- }
- if (isDef(res.timeout)) {
- timerTimeout = setTimeout(() => {
- timerTimeout = null
- if (isUndef(factory.resolved)) {
- reject(
- process.env.NODE_ENV !== 'production'
- ? `timeout (${res.timeout}ms)`
- : null
- )
- }
- }, res.timeout)
- }
- }
- }
- sync = false
- // return in case resolved synchronously
- return factory.loading
- ? factory.loadingComp
- : factory.resolved
- }
- }
|