Angular等待用户交互场景下Deferred模式的合法性及替代方案
关于Deferred模式使用的合理性
通常大家把Deferred归为反模式,针对的是两种滥用场景:
- 本可以直接在Promise构造函数内部完成异步操作封装(比如封装定时器、接口请求),却额外创建Deferred对象绕弯路,增加不必要的代码复杂度
- 不加封装直接把resolve/reject函数暴露到全局上下文,导致Promise状态可以被任意地方意外修改,引发不可预期的流程问题
你的实现完全避开了以上两个问题,属于合理使用:
- 你的业务场景天生存在Promise创建和resolve触发的时机、上下文分离的需求:Promise在中介服务创建Request实例时生成,而resolve逻辑要在组件侧接收用户交互后才触发,这种场景下Deferred是最直接、可读性最高的实现方案
- 你没有直接暴露私有属性
_resolve,而是封装了公开的respond方法作为唯一的触发入口,完全控制了Promise状态的修改路径,不存在状态失控的风险 - 你的业务明确不需要取消、超时、异常拒绝逻辑,当前实现完全匹配需求,不存在过度设计或者实现缺陷,完全可以正常投入使用。
可选的替代实现方案
如果后续你需要扩展能力(比如加超时、取消逻辑),或者想更贴合Angular技术栈的RxJS生态,可以用RxJS的AsyncSubject实现等价能力,AsyncSubject只会在完成后发射唯一的最终值,完全符合一次性请求的特性,示例实现如下:
import { AsyncSubject, firstValueFrom } from 'rxjs'; abstract class Request<T> { private readonly _responseSubject = new AsyncSubject<T>(); public get response(): Promise<T> { return firstValueFrom(this._responseSubject); } public respond(response: T): void { this._responseSubject.next(response); this._responseSubject.complete(); } }
这个实现和你原来的Deferred版本对外接口完全一致,不需要修改上层业务代码,同时可以很方便的扩展RxJS的操作符实现超时、取消等能力。
内容的提问来源于stack exchange,提问作者Dario Scattolini
相关产品推荐
相关产品推荐

