代码 Vue 3.6 RC 把异步组件的 200ms 延迟加回来了:loading 闪一下到底该谁管

2026-10-26 21:05:48

Vue 3.6 RC 把异步组件的 200ms 延迟加回来了:loading 闪一下到底该谁管

v3.6.0-rc.13 的 changelog 里有一条 runtime-core 的修复:

runtime-core: restore the default 200ms delay of async loading components (#15950)

这里的 restore 说明,3.6 RC 过程中这层默认延迟被去掉或改动过,rc.13 又把它恢复了。改动只有一行,但会影响所有使用 defineAsyncComponent 并且配置了 loadingComponent 的页面。

完整 changelog:

默认 delay 的行为

defineAsyncComponent 的 delay 决定异步组件加载多久之后才渲染 loadingComponent,默认 200ms。

loader 在 200ms 内 resolve,loadingComponent 根本不会进入渲染,真实组件直接出现——快网络下用户看不到 skeleton 闪一下。超过 200ms 才挂上 loading,慢网络下才有占位反馈。

import { defineAsyncComponent } from 'vue'

const AsyncPanel = defineAsyncComponent({
loader: () => import('./Panel.vue'),
loadingComponent: PanelSkeleton,
delay: 200,          // 默认值;写成 0 就是立刻显示 loading
timeout: 5000,       // 超时进入错误流程
errorComponent: PanelError,
onError(err, retry, fail, attempts) {
// 重试 / 放弃
}
})

delay 和 timeout 是两个独立计时器,不要混:delay 管「什么时候显示 loading」,timeout 管「多久算失败」。timeout 默认值需按官方文档核对。

Suspense 下由谁管 loading

异步组件默认 suspensible: true。放在 `` 子树里时,等待由 Suspense 的 #fallback 承担,组件自己的 loadingComponent / delay 不参与渲染。要给 Suspense 内的异步组件单独配 loading,需要显式 suspensible: false;具体行为建议对照官方文档核对。

实际项目里常见双份 loading:外层 `` 有 #fallback,异步组件又配了 loadingComponent。3.6 恢复默认延迟后,这种写法在 Suspense 内通常只走 fallback,另一份是死代码——删掉比留着安全。

复现验证

  1. Chrome DevTools → Network,限速选 Fast 4G / Slow 3G。
  2. 硬刷新触发异步 chunk 请求,观察 loading 是否在快网络下闪一下。默认 delay: 200 时,本地或 Fast 4G 通常看不到 loading;Slow 3G 能看到。
  3. 把同一组件改成 delay: 0,再刷一次,快网络下 loading 应该明显出现一帧——两次对比即确认延迟生效。
  4. 切换限速到离线 / 极慢,配合 timeout 观察 errorComponent。

区分「网络慢」和「真失败」:

  • 慢只是慢,最终 resolve,走的是 delay → loading → 真实组件这条路径。
  • 真失败(chunk 404、动态 import 抛错、timeout 触发)走 onError,再由 errorComponent 兜底 UI。
  • onError 里做重试与埋点,errorComponent 只负责展示,不要在上报里把慢请求当成错误统计。

升级迁移注意

3.6 RC 早期版本没有这层默认延迟,有人自己在外面包了一层防抖 loading(setTimeout 200ms 后再 showLoading = true)。升到 rc.13 后,这层手写防抖会和内置 delay 叠加,实际延迟变成约 400ms,慢网络下会感觉 loading 出现得「卡一下」。

处理方式二选一:

  • 删掉手写防抖,交给内置 delay;
  • 或者保留自己的逻辑,同时显式 delay: 0,避免双计时器。

反过来,如果有交互依赖「点击后立刻出 skeleton」的即时反馈,升级后需要主动写 delay: 0,否则 200ms 内什么都没发生。

细节以官方文档 defineAsyncComponent 一节为准:

复制全文 生成海报 Vue 前端 异步组件

推荐文章

程序员茄子在线接单