UNPKG

3.52 kBJavaScriptView Raw
1/* @flow */
2
3import {
4 warn,
5 once,
6 isDef,
7 isUndef,
8 isTrue,
9 isObject,
10 hasSymbol,
11 isPromise
12} from 'core/util/index'
13
14import { createEmptyVNode } from 'core/vdom/vnode'
15
16function ensureCtor (comp: any, base) {
17 if (
18 comp.__esModule ||
19 (hasSymbol && comp[Symbol.toStringTag] === 'Module')
20 ) {
21 comp = comp.default
22 }
23 return isObject(comp)
24 ? base.extend(comp)
25 : comp
26}
27
28export function createAsyncPlaceholder (
29 factory: Function,
30 data: ?VNodeData,
31 context: Component,
32 children: ?Array<VNode>,
33 tag: ?string
34): VNode {
35 const node = createEmptyVNode()
36 node.asyncFactory = factory
37 node.asyncMeta = { data, context, children, tag }
38 return node
39}
40
41export function resolveAsyncComponent (
42 factory: Function,
43 baseCtor: Class<Component>,
44 context: Component
45): Class<Component> | void {
46 if (isTrue(factory.error) && isDef(factory.errorComp)) {
47 return factory.errorComp
48 }
49
50 if (isDef(factory.resolved)) {
51 return factory.resolved
52 }
53
54 if (isTrue(factory.loading) && isDef(factory.loadingComp)) {
55 return factory.loadingComp
56 }
57
58 if (isDef(factory.contexts)) {
59 // already pending
60 factory.contexts.push(context)
61 } else {
62 const contexts = factory.contexts = [context]
63 let sync = true
64
65 const forceRender = (renderCompleted: boolean) => {
66 for (let i = 0, l = contexts.length; i < l; i++) {
67 contexts[i].$forceUpdate()
68 }
69
70 if (renderCompleted) {
71 contexts.length = 0
72 }
73 }
74
75 const resolve = once((res: Object | Class<Component>) => {
76 // cache resolved
77 factory.resolved = ensureCtor(res, baseCtor)
78 // invoke callbacks only if this is not a synchronous resolve
79 // (async resolves are shimmed as synchronous during SSR)
80 if (!sync) {
81 forceRender(true)
82 } else {
83 contexts.length = 0
84 }
85 })
86
87 const reject = once(reason => {
88 process.env.NODE_ENV !== 'production' && warn(
89 `Failed to resolve async component: ${String(factory)}` +
90 (reason ? `\nReason: ${reason}` : '')
91 )
92 if (isDef(factory.errorComp)) {
93 factory.error = true
94 forceRender(true)
95 }
96 })
97
98 const res = factory(resolve, reject)
99
100 if (isObject(res)) {
101 if (isPromise(res)) {
102 // () => Promise
103 if (isUndef(factory.resolved)) {
104 res.then(resolve, reject)
105 }
106 } else if (isPromise(res.component)) {
107 res.component.then(resolve, reject)
108
109 if (isDef(res.error)) {
110 factory.errorComp = ensureCtor(res.error, baseCtor)
111 }
112
113 if (isDef(res.loading)) {
114 factory.loadingComp = ensureCtor(res.loading, baseCtor)
115 if (res.delay === 0) {
116 factory.loading = true
117 } else {
118 setTimeout(() => {
119 if (isUndef(factory.resolved) && isUndef(factory.error)) {
120 factory.loading = true
121 forceRender(false)
122 }
123 }, res.delay || 200)
124 }
125 }
126
127 if (isDef(res.timeout)) {
128 setTimeout(() => {
129 if (isUndef(factory.resolved)) {
130 reject(
131 process.env.NODE_ENV !== 'production'
132 ? `timeout (${res.timeout}ms)`
133 : null
134 )
135 }
136 }, res.timeout)
137 }
138 }
139 }
140
141 sync = false
142 // return in case resolved synchronously
143 return factory.loading
144 ? factory.loadingComp
145 : factory.resolved
146 }
147}