setup 不能是 async 函数,因为会返回 promise 导致模板无法访问响应式数据、生命周期钩子失效;正确方式是用 defineasynccomponent 或 顶层 await(vue 3.4+),或在组合函数中分离 load 方法手动调用。

不能在 setup 顶层直接用 async 函数,因为这会让 setup 返回一个 Promise,模板无法访问其中的响应式变量——Vue 会把整个组件当作“异步组件”处理,但此时 <suspense></suspense> 并不会自动生效,除非你显式把它变成一个异步组件。
为什么 setup 不能是 async 函数
setup 是 Composition API 的入口,它的返回值必须是一个对象(供模板使用),或一个渲染函数。一旦标记为 async,返回值就变成 Promise<object></object>,Vue 模板系统无法解包这个 Promise,导致数据不可见、绑定失效,甚至生命周期钩子(如 onMounted)注册失败、引发内存泄漏。
正确配合 Suspense 的方式:用 defineAsyncComponent
要让 <suspense></suspense> 生效,必须让组件本身是“异步加载”的,而不是在 setup 内部做 await。推荐做法是把需要异步初始化的逻辑封装进一个子组件,再用 defineAsyncComponent 动态导入它:
- 父组件中用
<suspense></suspense>包裹该子组件 - 子组件自身使用普通
setup,在onMounted或组合函数中触发异步操作(如useProfile(id).load()) - 子组件内部管理 loading 状态、错误状态,或通过
v-if控制内容显示
替代方案:顶层 await(仅限 .vue 单文件组件)
Vue 3.4+ 支持在 <script setup></script> 中使用顶层 await,但需满足两个条件:
- 脚本必须是
<script setup lang="ts"></script>或lang="js" - 组件会被自动包装为异步组件,
<suspense></suspense>可捕获其加载过程
示例:
<script setup lang="ts"><br> const data = await api.fetchUserProfile()<br> </script>此时 Vue 编译器会自动将其转为 defineAsyncComponent 形式,<suspense></suspense> 能正常接管 fallback 显示。
组合函数里不要 await,只构造可调用的 load 方法
像 useProfile 这类组合函数,应避免在 setup 里 await useProfile(id).load(),而应:
- 在 setup 中调用
const { profile, load } = useProfile(id) - 在
onMounted或用户交互时手动执行load() - 配合
v-if="$pending"或状态字段控制 UI,而非依赖 Suspense
这样更可控,也兼容非 Suspense 场景(比如 SSR 或微前端子应用)。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











