我目前正在教自己使用rxjs进行反应性编程,并且我已经为自己设置了一个创建可观察流的挑战,无论如何都会向订阅者发出相同的结果。
我已经记住了HTTP" GET"的创建。给定一个特定URL的流,我试图每两秒对该流进行操作,结果是对于计时器的每个滴答,我将从原始流中提取缓存/记忆的HTTP结果
import superagent from 'superagent';
import _ from 'lodash';
// Cached GET function, returning a stream that emits the HTTP response object
var httpget = _.memoize(function(url) {
var req = superagent.get(url);
req = req.end.bind(req);
return Rx.Observable.fromNodeCallback(req)();
});
// Assume this is created externally and I only have access to response$
var response$ = httpget('/ontologies/acl.ttl');
// Every two seconds, emit the memoized HTTP response
Rx.Observable.timer(0, 2000)
.map(() => response$)
.flatMap($ => $)
.subscribe(response => {
console.log('Got the response!');
});
我确信我必须在某处调用replay()
,但无论我做什么,都会每两秒启动一次新的HTTP呼叫。我如何构造它以便我可以从URL构造一个observable并让它始终向任何后续订阅者发出相同的HTTP结果?
修改
我找到了一种方法来获得我想要的结果,但我觉得我错过了一些东西,并且应该能够通过更加简化的方法重构它:
var httpget = _.memoize(function(url) {
var subject = new Rx.ReplaySubject();
try {
superagent.get(url).end((err, res) => {
if(err) {
subject.onError(err);
}
else {
subject.onNext(res);
subject.onCompleted();
}
});
}
catch(e) {
subject.onError(e);
}
return subject.asObservable();
});
答案 0 :(得分:1)
您的第一个代码示例实际上更接近于执行此操作的方式
var httpget = _.memoize(function(url) {
var req = superagent.get(url);
return Rx.Observable.fromNodeCallback(req.end, req)();
});
但是,这不起作用,因为fromNodeCallback
中似乎存在错误。至于解决这个问题,我认为你实际上是在寻找AsyncSubject
而不是ReplaySubject
。后者可以工作,但前者是针对这种情况而设计的(如果对您而言,并没有数组创建的开销+缓存过期的运行时检查)。
var httpget = _.memoize(function(url) {
var subject = new Rx.AsyncSubject();
var req = superagent.get(url);
Rx.Observable.fromNodeCallback(req.end, req)().subscribe(subject);
return subject.asObservable();
});
最后,虽然map
感谢您正在考虑这一点,但您可以使用直接timer
的{{1}}重载来简化您的flatMap
代码:
Observable
答案 1 :(得分:0)
除非我的问题出错,否则 list1 <- as.list(list1)
list2 <- as.list(list2)
do.call(paste0, expand.grid(list1, list2))
#[1] "X1" "Y1" "X2" "Y2" "X3" "Y3"
会为您解决问题,它会缓存您的观察值的最后一个值。
此代码发送一次请求,然后每200 ms给出相同的缓存响应:
Observable.combineLatest