Blame view

node_modules/vue/src/v3/apiAsyncComponent.ts 2.9 KB
4cd4fd28   郭伟龙   feat: 初始化项目
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import { warn, isFunction, isObject } from 'core/util'

interface AsyncComponentOptions {
  loader: Function
  loadingComponent?: any
  errorComponent?: any
  delay?: number
  timeout?: number
  suspensible?: boolean
  onError?: (
    error: Error,
    retry: () => void,
    fail: () => void,
    attempts: number
  ) => any
}

type AsyncComponentFactory = () => {
  component: Promise<any>
  loading?: any
  error?: any
  delay?: number
  timeout?: number
}

/**
 * v3-compatible async component API.
 * @internal the type is manually declared in <root>/types/v3-define-async-component.d.ts
 * because it relies on existing manual types
 */
export function defineAsyncComponent(
  source: (() => any) | AsyncComponentOptions
): AsyncComponentFactory {
  if (isFunction(source)) {
    source = { loader: source } as AsyncComponentOptions
  }

  const {
    loader,
    loadingComponent,
    errorComponent,
    delay = 200,
    timeout, // undefined = never times out
    suspensible = false, // in Vue 3 default is true
    onError: userOnError
  } = source

  if (__DEV__ && suspensible) {
    warn(
      `The suspensiblbe option for async components is not supported in Vue2. It is ignored.`
    )
  }

  let pendingRequest: Promise<any> | null = null

  let retries = 0
  const retry = () => {
    retries++
    pendingRequest = null
    return load()
  }

  const load = (): Promise<any> => {
    let thisRequest: Promise<any>
    return (
      pendingRequest ||
      (thisRequest = pendingRequest =
        loader()
          .catch(err => {
            err = err instanceof Error ? err : new Error(String(err))
            if (userOnError) {
              return new Promise((resolve, reject) => {
                const userRetry = () => resolve(retry())
                const userFail = () => reject(err)
                userOnError(err, userRetry, userFail, retries + 1)
              })
            } else {
              throw err
            }
          })
          .then((comp: any) => {
            if (thisRequest !== pendingRequest && pendingRequest) {
              return pendingRequest
            }
            if (__DEV__ && !comp) {
              warn(
                `Async component loader resolved to undefined. ` +
                  `If you are using retry(), make sure to return its return value.`
              )
            }
            // interop module default
            if (
              comp &&
              (comp.__esModule || comp[Symbol.toStringTag] === 'Module')
            ) {
              comp = comp.default
            }
            if (__DEV__ && comp && !isObject(comp) && !isFunction(comp)) {
              throw new Error(`Invalid async component load result: ${comp}`)
            }
            return comp
          }))
    )
  }

  return () => {
    const component = load()

    return {
      component,
      delay,
      timeout,
      error: errorComponent,
      loading: loadingComponent
    }
  }
}