推荐使用静态工厂方法 async create() 封装异步初始化,先完成依赖加载再实例化;或提供带 Promise 缓存的显式 init() 方法;构造函数仅做必要同步准备,业务方法应安全 await 并转换错误。

构造函数本身不能处理异步初始化,这是 JavaScript 语言机制决定的——它必须同步返回实例,不支持 await,也不能返回 Promise。所谓“提升体验”,不是绕过这个限制,而是用更清晰、可控、可复用的方式组织初始化逻辑,让调用方感知不到等待过程的混乱,同时避免竞态、重复请求和未初始化就调用的错误。
用静态工厂方法 async create() 封装创建与加载
这是最推荐的模式,尤其适合需要“开箱即用”的场景(如 SDK 客户端、配置管理器)。调用方只需 await MyClass.create(...),拿到的就是已准备就绪的实例。
- 工厂内部先完成所有异步依赖(如 fetch 配置、校验 token、连接 WebSocket),再实例化类并注入结果
- 错误统一在工厂内捕获并抛出,调用方无需额外写
.catch或try/catch包裹初始化步骤 - 语义明确:create = 创建 + 初始化,不是“创建后还要手动 init”
提供显式 init() 方法并缓存 Promise 状态
适合允许部分功能提前使用、或初始化时机由业务决定的场景(如页面加载后延迟加载用户数据)。
- 在类内用私有字段(如
#initPromise)缓存首次init()返回的 Promise - 后续调用直接返回该 Promise,自动去重、避免竞态,也方便重试(
await obj.init()可多次安全调用) - 其他方法(如
getData())开头检查:if (!this.#initPromise) throw new Error('请先调用 init()'),或直接await this.#initPromise
构造函数只做最小同步准备
这是所有方案的基础前提。构造函数里只干三件事:
- 校验必要参数(如 URL、ID 是否为空)
- 赋值基础属性(
this.url = url、this.id = id) - 初始化空状态(
this.#data = null、this.#initPromise = null)
在业务方法中安全使用 await 并做好错误转换
类的方法可以是 async 的,但不要把错误甩给调用方处理。
- 每个
async方法内部用try/catch捕获底层异常(如网络超时、401) - 将原始错误包装成业务语义明确的错误(如
new AuthError('登录态失效')),便于上层统一提示或跳转 - 对依赖初始化的方法,优先检查状态再执行,而不是盲目
await—— 避免每次调用都触发初始化逻辑











