Vue: Async Components
2022-03-28
0. Intro
基本用法
在大型的应用中,我们可以需要把 app 分解成小块,只在需要的时候从 server 加载一个 component。Vue 是通过一个 defineAsyncComponent 的功能来达成我们想要的这个效果的。
import { defineAsyncComponent } from 'vue'
const AsyncComp = defineAsyncComponent(() => {
  return new Promise((resolve, reject) => {
    // ...load component from server
    resolve(/* loaded component */)
  })
})
// ... use `AsyncComp` like a normal component
这个 function 会接收一个 loader function,loader function 会返回一个 Promise。
当你从 server 接收到了你的 component definition 时,Promise 的 resolve callback 会被调用。
我们也可以调用 reject(reason)来表示加载失败。
Wrapper Component
ES module dynamic import also returns a Promise, so most of the time we will use it in combination with
defineAsyncComponent.
Vite 和 webpack 之类的 bundler 也支持这种语法,所以我们可以用它来 import Vue SFC:
import { defineAsyncComponent } from 'vue'
const AsyncComp = defineAsyncComponent(() =>
  import('./components/MyComponent.vue')
)
上面例子中的 AsyncComp 是一个 wrapper component,只有当 component 在 page 上被渲染时才会调用 loader function。
另外,它(wrapper)会把所有的 props 都传入 inner component,所以我们可以用这个 async wrapper 来替代 original component,同时还能达到 lazy loading 的效果。
Use defineAsyncComponent when registering a component locally
import { defineAsyncComponent } from 'vue'
export default {
  // ...
  components: {
    AsyncComponent: defineAsyncComponent(() =>
      import('./components/AsyncComponent.vue')
    )
  }
}
1. Loading and Error States
因为我们用了异步操作,所以会有 loading 和 error 的状态,我们可以通过 advanced options 来处理这些 states。
const AsyncComp = defineAsyncComponent({
  // the loader function
  loader: () => import('./Foo.vue'),
  // A component to use while the async component is loading
  loadingComponent: LoadingComponent,
  // Delay before showing the loading component. Default: 200ms.
  delay: 200,
  // A component to use if the load fails
  errorComponent: ErrorComponent,
  // The error component will be displayed if a timeout is
  // provided and exceeded. Default: Infinity.
  timeout: 3000
})
假如提供了 loading component,这个 component 会在 inner component 加载的时候显示(会有默认的 200ms 延迟)。
There is a default 200ms delay before the loading component is shown - this is because on fast networks, an instant loading state may get replaced too fast and end up looking like a flicker.
假如提供了 error component,当 Promise returned by the loader function is rejected 时,会显示 error component。
你也可以定义 timeout,当 request 时间过长时显示 error component。
2. Using with Suspense
异步组件可以跟 <Suspense> 组件一起使用。