Promise是底层基石、async/await是主力表达层,二者协同:统一用async函数封装所有顶层异步入口,API返回Promise但调用方一律await消费,错误由try/catch统一捕获并按业务码分类处理,禁止裸写.then或在生命周期钩子中直接new Promise。

在企业级大型单页应用(SPA)中,确立基于 JavaScript 异步对象的最优范式,核心不是追求“最新语法”,而是围绕可维护性、错误可控性、执行时序明确性、调试友好性四个刚性目标来设计。Promise 是底层基石,async/await 是主力表达层,二者必须协同,不能割裂使用。
统一用 async/await 封装所有异步入口点
路由守卫、API 请求封装、组件初始化逻辑等顶层异步入口,全部定义为 async 函数。这能天然规避 .then 链断裂、避免忘记 return Promise 导致链式中断。
- 每个 API 调用函数返回 Promise,但调用方一律用 await 消费,不裸写 .then()
- 错误统一由 try/catch 捕获,配合业务错误码分类处理(如重试、跳登录、Toast 提示)
- 禁止在组件生命周期钩子(如 mounted、useEffect)中直接 new Promise 或嵌套 .then —— 全部收口到独立的 async service 函数中
Promise 链仅用于组合与编排,不用于业务流程控制
当需要串行依赖(B 必须等 A 结果)、并行聚合(A 和 B 同时发起,等都完成)、竞速选取(取最快响应)时,才显式使用 Promise.all、Promise.race、Promise.allSettled 等静态方法。它们是“编排原语”,不是“业务逻辑容器”。
- 例如:加载用户信息 + 用户权限 + 用户偏好 → 用 Promise.all 并发请求,失败时按字段粒度降级,而非逐个 .then 嵌套
- 例如:页面初始化需先校验登录态,再拉取配置,再渲染 → 用 await 顺序调用三个 async 函数,语义清晰、堆栈完整
- 避免把业务判断(如 if (res.code === 401))塞进 .then 回调里;应提前 resolve/reject 或抛出带类型标识的 Error 子类
微任务边界必须显式可控
Promise.then 回调属于微任务(microtask),会在当前宏任务结束、下一个宏任务开始前执行。大型 SPA 中若大量无节制地链式触发 .then,可能堆积微任务队列,造成 UI 响应延迟或内存滞留。
- 对非关键路径的副作用(如埋点上报、日志记录),改用 setTimeout(() => {}, 0) 推入宏任务队列,释放主线程
- 长链 Promise(超过 4 层)必须拆分为多个命名的 async 函数,便于监控和打断
- 所有未 catch 的 Promise 拒绝必须全局监听(window.addEventListener('unhandledrejection')),防止静默失败
拒绝状态必须携带上下文与可追溯标识
企业级系统要求错误可定位、可回溯、可聚合。单纯 throw new Error('failed') 或 reject('bad request') 不够。
- 自定义 BusinessError 类,包含 code(业务码)、requestId(请求唯一 ID)、timestamp、stack(可选)、cause(原始错误引用)
- 所有 fetch 封装统一拦截 response.status,非 2xx 主动 reject(BusinessError.fromResponse(...))
- 在 catch 或 unhandledrejection 中自动上报 Sentry,并附带当前路由、用户角色、设备 UA 等上下文
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











