在 Angular 中等待用户交互时延迟(反?-)模式的替代方案
Alternatives to Deferred (anti?-)pattern when awaiting for user interactions in Angular
我正在使用 Angular 构建游戏,它具有以下机制:
- Angular 服务检查游戏状态并请求所需的用户交互。
- 中介服务创建此请求并使用 RxJS 主题将其发送到相关 Angular 组件。
- 在此中介服务中等待对该请求的响应,在请求得到解决之前游戏不会继续。
- 组件通过调用
request.respond(response)
方法设置用户对请求的响应。
我需要提出一个 Request class 适合这个要求。由于请求一劳永逸地解决,我决定避免将其基于 RxJs Observable,并尝试使用 JavaScript Promise 代替。使用 async
/await
语法可以轻松等待 Promises,需求 (4) 让我找到了 the Deferred pattern。我为各种请求构建了这个基础class:
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);
}
}
我没有添加拒绝处理,因为我没有想出请求可能失败的情况。似乎甚至不需要暂停,因为游戏需要响应才能继续。
这非常适合我的目的,但后来我开始发现讨论将其视为 反模式(例如, and )。我不习惯使用 promises,所以我不完全理解暴露 resolve 函数的风险,我无法辨别这种模式何时合法,我也无法想象其他方式来满足我的要求使用答应。
我想知道这是否是使用延迟模式的合法方式,如果不是,是否有另一种方式来实现我的需要。
延迟反模式的问题不在于暴露 resolve
函数本身,而是在于将其与(或更糟的是,作为 promise 的一部分)一起暴露。您的请求 class 没有理由需要包含承诺。相反,您只需
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
class 中),但使用起来还没有问题。它真正成为反模式的地方是如果你这样做了
function sendRequest() {
const request = new Request();
mediator.send(request);
return request;
}
因为现在有人有一个“延迟对象”,而不仅仅是对响应的承诺。他们可能会滥用该功能:
const request = sendRequest();
request.respond("Ooops");
const response = await request.response;
这才是真正的危险:将延迟返回到不应解析承诺的代码。将 resolve
函数交给应该响应的组件是完全没问题的。
我正在使用 Angular 构建游戏,它具有以下机制:
- Angular 服务检查游戏状态并请求所需的用户交互。
- 中介服务创建此请求并使用 RxJS 主题将其发送到相关 Angular 组件。
- 在此中介服务中等待对该请求的响应,在请求得到解决之前游戏不会继续。
- 组件通过调用
request.respond(response)
方法设置用户对请求的响应。
我需要提出一个 Request class 适合这个要求。由于请求一劳永逸地解决,我决定避免将其基于 RxJs Observable,并尝试使用 JavaScript Promise 代替。使用 async
/await
语法可以轻松等待 Promises,需求 (4) 让我找到了 the Deferred pattern。我为各种请求构建了这个基础class:
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);
}
}
我没有添加拒绝处理,因为我没有想出请求可能失败的情况。似乎甚至不需要暂停,因为游戏需要响应才能继续。
这非常适合我的目的,但后来我开始发现讨论将其视为 反模式(例如,
我想知道这是否是使用延迟模式的合法方式,如果不是,是否有另一种方式来实现我的需要。
延迟反模式的问题不在于暴露 resolve
函数本身,而是在于将其与(或更糟的是,作为 promise 的一部分)一起暴露。您的请求 class 没有理由需要包含承诺。相反,您只需
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
class 中),但使用起来还没有问题。它真正成为反模式的地方是如果你这样做了
function sendRequest() {
const request = new Request();
mediator.send(request);
return request;
}
因为现在有人有一个“延迟对象”,而不仅仅是对响应的承诺。他们可能会滥用该功能:
const request = sendRequest();
request.respond("Ooops");
const response = await request.response;
这才是真正的危险:将延迟返回到不应解析承诺的代码。将 resolve
函数交给应该响应的组件是完全没问题的。