在 Angular 中等待用户交互时,可替代延迟(反?-)模式

Posted

技术标签:

【中文标题】在 Angular 中等待用户交互时,可替代延迟(反?-)模式【英文标题】:Alternatives to Deferred (anti?-)pattern when awaiting for user interactions in Angular 【发布时间】:2021-11-05 15:48:35 【问题描述】:

我正在使用具有以下机制的 Angular 构建游戏:

    Angular 服务检查游戏状态并请求所需的用户交互。 中介服务创建此请求并使用 RxJS 主题将其发送到相关的 Angular 组件。 在此中介服务中等待对此请求的响应,直到请求得到解决,游戏才会继续。 组件通过调用request.respond(response)方法设置用户对请求的响应。

我需要提出一个适合此要求的 Request 类。由于请求一劳永逸地解决,我决定避免将其基于 RxJs Observable,而是尝试使用 javascript Promise。使用 async/await 语法可以轻松地等待 Promise,而要求 (4) 让我了解了 the Deferred pattern。我为各种请求构建了这个基类:

abstract class Request<T> 
  private _resolve: (value: T) => void = () => ;

  private _response: Promise<T> = new Promise<T>(resolve => 
    this._resolve = resolve;
  );

  public get response(): Promise<T> 
    return this._response;
  

  public respond(response: T) 
    this._resolve(response);
  

我没有添加拒绝处理,因为我没有想出请求可能失败的情况。似乎甚至不需要超时,因为游戏需要响应才能继续。

这非常适合我的目的,但后来我开始发现讨论将此视为反模式(例如,this 和 this)。我不习惯使用 Promise,所以我不完全理解暴露解析功能的风险,我无法辨别这种模式何时合法的情况,我也无法想象使用其他方式来满足我的要求承诺。

我想知道这是否是使用 Deferred 模式的合法方式,如果不是,是否有另一种方式来实现我所需要的。

【问题讨论】:

【参考方案1】:

延迟反模式的问题不在于暴露resolve 函数本身,而在于暴露它与promise 一起(或更糟的是,作为promise 的一部分)。您的请求类没有理由需要包含承诺。相反,您需要做的只是

const response = await new Promise(resolve => 
  mediator.send( respond: resolve );
);

中介者只需要这个对象,处理请求的组件仍然可以简单地调用request.respond(response)。这比做简单得多

const request = new Request();
mediator.send(request);
const response = await request.response;

这可能是不必要的复杂(与Request 类中的所有代码),但使用还没有问题。它真正成为反模式的地方是如果你这样做了

function sendRequest() 
  const request = new Request();
  mediator.send(request);
  return request;

因为现在有人有一个“延迟对象”,而不仅仅是响应的承诺。他们可能会滥用该功能:

const request = sendRequest();
request.respond("Ooops");
const response = await request.response;

这是真正的危险:返回一个不应该解决承诺的延迟代码。将resolve 函数交给应该响应的组件是完全没问题的。

【讨论】:

我仍然需要派生的Request 对象,其中包含要在组件中显示的信息。如果将resolve 函数交给组件是安全的,我想我可以在promise 执行器中创建Request 实例,并使用resolve 函数作为参数,以便响应方法可以使用它:new Promise(resolve =&gt; mediator.send(new Request(data, resolve)); ) 是的,完全正确 - 只需在构造函数中执行 this.respond = resolve 即可。我的意思是您也可以将data 放在对象文字中,但我假设您的class 有一些额外的方法,这些方法比您问题中代码中的promise getter 更有用:-) 感谢您的回答,它绝对简化了代码并澄清了延迟对象的问题! 事实上,只要简单的接口和对象字面量就可以了!

以上是关于在 Angular 中等待用户交互时,可替代延迟(反?-)模式的主要内容,如果未能解决你的问题,请参考以下文章

让工作线程在 GUI 线程中等待用户输入? Python/PyQt

Angular开发者指南服务

在java中等待客户端响应的正确方法是啥?

Angular CanLoad 防护仅在第一次延迟加载时触发一次?

Angular 7、Ngrx、Rxjs 6 - 访问延迟加载模块之间的状态

如何使用 Angular 延迟加载模块克服加载块失败的问题