1 |
|
2 |
|
3 | import {
|
4 | warn,
|
5 | once,
|
6 | isDef,
|
7 | isUndef,
|
8 | isTrue,
|
9 | isObject,
|
10 | hasSymbol,
|
11 | isPromise
|
12 | } from 'core/util/index'
|
13 |
|
14 | import { createEmptyVNode } from 'core/vdom/vnode'
|
15 |
|
16 | function 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 |
|
28 | export 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 |
|
41 | export 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 |
|
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 |
|
77 | factory.resolved = ensureCtor(res, baseCtor)
|
78 |
|
79 |
|
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 |
|
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 |
|
143 | return factory.loading
|
144 | ? factory.loadingComp
|
145 | : factory.resolved
|
146 | }
|
147 | }
|