人人都会AI编程

组件懒加载与加载态、错误态处理

更新时间:2026-07-10

当应用体积增大,把所有组件一次性打包进主文件会让首屏加载变慢。组件懒加载的思路是:只在组件真正需要渲染时,才去加载对应的代码。在 Vue 中,这通过异步组件实现。

基础用法:defineAsyncComponent

Vue 3 提供了 defineAsyncComponent 方法,用来定义一个异步组件。结合 ES 的动态 import(),可以实现按需加载:

import { defineAsyncComponent } from 'vue'

const AsyncModal = defineAsyncComponent(() => import('./Modal.vue'))

然后在模板中像普通组件一样使用:

<template>
  <button @click="show = true">打开弹窗</button>
  <AsyncModal v-if="show" @close="show = false" />
</template>

<script setup>
import { ref, defineAsyncComponent } from 'vue'
const show = ref(false)
const AsyncModal = defineAsyncComponent(() => import('./Modal.vue'))
</script>

只有当 showtrue 时,Modal.vue 及其依赖的代码才会被加载,打包工具(Vite/Webpack)会自动将其拆分成独立的 chunk。

处理加载状态:Loading 与 Error

用户等待组件下载时需要给反馈,加载失败时也需要兜底处理。defineAsyncComponent 支持传入一个配置对象,让你轻松处理这些状态:

const AsyncProfile = defineAsyncComponent({
  // 工厂函数,返回一个 Promise
  loader: () => import('./UserProfile.vue'),

  // 加载中显示的组件
  loadingComponent: () => import('./LoadingSpinner.vue'),

  // 加载失败后显示的组件
  errorComponent: () => import('./ErrorRetry.vue'),

  // 展示加载组件前的延迟时间,默认 200ms
  delay: 200,

  // 超时时间,超过该时间则显示错误组件,默认 Infinity
  timeout: 3000
})
  • delay:避免网络极快时出现“闪现”的加载动画。比如设定 200ms,那么如果组件在 200ms 内加载完成,加载组件就不会出现。
  • timeout:设定一个超时,超时后将 errorComponent 视为永久错误状态。若不设定,则一直等待。

错误重试机制

默认情况下,异步组件加载失败后会永久停留在错误组件。实际产品中往往需要“点击重试”。这可以通过 errorComponent 内部逻辑,或利用 onError 回调配合显隐控制来实现。

简易重试:利用 v-if 触发重新加载

通过 keyv-if 强制组件销毁重建,会重新触发 loader,相当于重试。

<template>
  <button @click="show = true">加载用户信息</button>
  <AsyncProfile v-if="show" :key="retryKey" />
</template>

<script setup>
import { ref } from 'vue'
const show = ref(false)
const retryKey = ref(0)

// 错误展示组件内部通过 emit 调用此方法
function handleRetry() {
  retryKey.value++   // 改变 key 会强制重建异步组件,触发重新加载
}
</script>

更精细的重试控制:结合 onError 回调

defineAsyncComponent 的完整配置中,可以传入 onError 钩子,它接收错误对象和一个 retry 函数。你可以在这里实现带次数限制的自动重试:

let retryCount = 0
const AsyncRemote = defineAsyncComponent({
  loader: () => import('./RemoteWidget.vue'),
  onError(error, retry, fail) {
    if (retryCount < 3) {
      retryCount++
      retry()   // 调用 retry 重新执行 loader
    } else {
      retryCount = 0
      fail()    // 放弃重试,转为 errorComponent
    }
  }
})

注意:onError 只用于加载过程中的错误处理,超时不会触发 onError(会直接走 errorComponent)。

真实场景建议

  • 路由级别的懒加载更简单,直接在路由配置中使用 component: () => import('...'),Vue Router 会同样进行代码分割。
  • 组件级的懒加载适合大型组件(图表、编辑器、复杂表单),这些组件只存在于特定交互中,不进入首屏。
  • 加载态和错误态的 UI 要保持轻量,避免它们的代码体积过大反而拖慢了初次加载。
  • 注意异步组件自身的样式隔离(scoped 仍然有效),加载错误时的兜底组件应提供明确的用户指引,而非空白。

通过异步组件 + 加载/错误处理,你可以把大型应用的初始包体缩小到极致,同时保持友好的用户体验。