我正在使用RxJs创建一个交互式网页。
这就是我想要实现的目标:
我有一个生成令牌的应用程序。这些令牌可以被外部实体使用。
当用户创建令牌时,页面开始轮询Web服务器的状态(是否消耗)。使用令牌时,页面会刷新。
因此,当创建令牌时,会每2秒向服务器发送一个请求,询问该令牌是否已被使用。
我有Observable
个字符串代表我的generatedTokens
。
我实际上已经有了一个使用Rx.Scheduler.default类的工作实现,它允许我手动完成任务。但是,我不禁觉得应该有一个更简单,更优雅的解决方案。
这是当前的代码:
class TokenStore {
constructor(tokenService, scheduler) {
// actual implementation omitted for clarity
this.generatedTokens = Rx.Observable.just(["token1", "token2"]);
this.consumedTokens = this.generatedTokens
.flatMap(token =>
Rx.Observable.create(function(observer) {
var notify = function() {
observer.onNext(token);
observer.onCompleted();
};
var poll = function() {
scheduler.scheduleWithRelative(2000, function() {
// tokenService.isTokenConsumed returns a promise that resolves with a boolean
tokenService.isTokenConsumed(token)
.then(isConsumed => isConsumed ? notify() : poll());
}
);
};
poll();
}));
}
}
是否有类似“repeatUntil”的方法?我正在寻找一个与上面代码完全相同的实现,但看起来更像是这样:
class TokenStore {
constructor(tokenService, scheduler) {
// actual implementation omitted for clarity
this.generatedTokens = Rx.Observable.just(["token1", "token2"]);
this.consumedTokens = this.generatedTokens
.flatMap(token =>
Rx.Observable.fromPromise(tokenService.isTokenConsumed(token))
.delay(2000, scheduler)
// is this possible?
.repeatUntil(isConsumed => isConsumed === true));
}
}
答案 0 :(得分:3)
有趣的是,在发布问题几分钟之后,答案让我感到震惊。我认为橡胶涂层可能不会那么愚蠢。
无论如何,答案包括两部分:
使用repeat()
,filter()
和first()
fromPromise
有一些内部延迟缓存机制,导致后续订阅不会触发新的AJAX请求。因此,我不得不使用Rx.Observable.create
解决方案:
class TokenStore {
constructor(tokenService, scheduler) {
// actual implementation omitted for clarity
this.generatedTokens = Rx.Observable.just(["token1", "token2"]);
this.consumedTokens = this.generatedTokens
.flatMap(token =>
// must use defer otherwise it doesnt retrigger call upon subscription
Rx.Observable
.defer(() => tokenService.isTokenConsumed(token))
.delay(2000, scheduler)
.repeat()
.filter(isConsumed => isConsumed === true)
.first())
.share();
}
}
次要的旁注:"分享()"确保两个observable都很热,这避免了每个订阅者都会导致ajax请求开始触发的情况。
答案 1 :(得分:0)
class TokenSource {
constructor(tokenService, scheduler) {
this.generatedTokens = Rx.Observable.just(["token1", "token2"]).share();
this.consumedTokens = this.generatedTokens
.flatMap(token =>
Rx.Observable.interval(2000, scheduler)
.flatMap(Rx.Observable.defer(() =>
tokenService.isTokenConsumed(token)))
.first(isConsumed => isConsumed === true))
.share()
}
}
您可以利用两个事实:
flatMap
有一个重载,它带有一个可观察的信息,每次新事件发生时都会被重新订阅
defer
可以使用返回promise的方法。该方法将在每次订阅时重新执行,这意味着您不必滚动自己的Promise
- > Observable
转化。