路由守卫中 await 会阻塞导航致骨架屏无法渲染;应将鉴权等异步逻辑移至组件内,配合 suspense + 异步组件、v-if="loaded" 或布局层统一控制骨架屏显隐,并对必需的守卫 await 设置超时兜底。

核心问题在于:路由守卫(如 beforeEach)中使用 await 会阻塞导航流程,导致 <router-view></router-view> 暂不挂载、骨架屏组件根本不会被创建或渲染——用户看到的不是“骨架在动”,而是空白或旧页面卡住。
避免在全局前置守卫中执行耗时 await
Vue Router 的 beforeEach 是同步拦截点,若其中 await api.checkAuth() 耗时 800ms,整个路由切换就会延迟 800ms,骨架屏甚至没机会触发 mounted。
- 把鉴权、权限校验等逻辑移到目标组件内部(配合
v-if="loaded"+ 骨架屏) - 守卫中只做轻量判断:比如检查本地 token 是否存在、过期时间是否明显超限
- 真正需要服务端验证的,改用「异步组件 + Suspense」或「组件内 loading 状态」接管
用 Suspense + 异步组件替代守卫级 await
让骨架屏成为组件加载过程的一部分,而非依赖路由守卫完成后再渲染:
当代理已经知道网站路由或内容URL,并且在启动前需要有效的sitemap XML、sitemap索引或robots.txt引用时,请使用sitemap。这是一个发布构件技能,而不是爬虫或SEO平台。
- 将页面组件定义为
defineAsyncComponent,并在模板中包裹<suspense></suspense> -
<template></template>内直接写骨架屏结构(非条件渲染,是原生占位) - 组件自身的
setup中可安全await,此时骨架屏已在 DOM 中稳定存在
提前激活骨架屏,与数据获取解耦
骨架屏不应等待任何异步结果才出现——它应在路由解析完成、组件开始加载时立即呈现:
- 在布局组件(如
DefaultLayout.vue)中统一控制骨架屏显隐,用router-view的v-slot="{ Component }"判断是否正在切换 - 配合
useRoute().matched.length或自定义 meta 字段(如needsData: true),按需启用骨架层 - 避免在 store action 中
await后再 commit 骨架状态——响应式更新本身有微任务延迟,可能错过首帧
对必须守卫中 await 的场景加超时兜底
极少数强一致性要求(如强制登出未过期 token)仍需守卫 await,但必须防止无限等待:
- 用
Promsie.race([apiCall(), new Promise(r => setTimeout(r, 1500))])设定硬性超时 - 超时后跳转到轻量 fallback 页面(如「加载中…」静态页),同时后台继续请求
- 后续通过事件总线或 pinia state 更新主页面数据,实现“先见后补”










