我是RxJs的新手,并且很难以" RxJs方式实现这一目标":
无限流a$
偶尔会发出一个值a
。
async()
接受a
并执行异步操作。
如果a$
在async
处于待处理状态时发出值,则只保留最新的al
。
在上一个async
完成后,如果有al
,请运行async(al)
。
等等。
a$:----a1----------a2----a3-----------------------a4-----------
async(a1):------------end async(a4):---
async(a3):-----end
这是我提出的,有点讨厌:
var asyncIdle$ = new Rx.BehaviorSubject()
var asyncRunning$ = new Rx.Subject()
var async$ = asyncIdle$
function async (val) {
async$ = asyncRunning$
// do something with val
console.log(val + ' handling')
setTimeout(() => {
console.log(val + ' complete')
async$.next()
async$ = asyncIdle$
}, 2000)
}
// simulate a$
var a$ = Rx.Observable.fromEvent(document, 'click')
.mapTo(1)
.scan((acc, curr) => acc + curr)
.do(val => console.log('got ' + val))
a$.debounce(() => async$)
.subscribe(val => {
async(val)
})
答案 0 :(得分:1)
您可以使用audit
operator来解决问题,这样(评论应该解释它是如何工作的):
// Simulate the source.
const source = Rx.Observable.merge(
Rx.Observable.of(1).delay(0),
Rx.Observable.of(2).delay(10),
Rx.Observable.of(3).delay(20),
Rx.Observable.of(4).delay(150),
Rx.Observable.of(5).delay(300)
).do(value => console.log("source", value));
// Simulate the async task.
function asyncTask(value) {
return Rx.Observable
.of(value)
.do(value => console.log(" before async", value))
.delay(100)
.do(value => console.log(" after async", value));
}
// Compose an observable that's based on the source.
// Use audit to ensure a value is not emitted until
// the async task has been performed.
// Use share so that the signal does not effect a
// second subscription to the source.
let signal;
const audited = source
.audit(() => signal)
.mergeMap(value => asyncTask(value))
.share();
// Compose a signal from the audited observable to
// which the async task is applied.
// Use startWith so that the first emitted value
// passes the audit.
signal = audited
.mapTo(true)
.startWith(true);
audited.subscribe(value => console.log("output", value));
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://unpkg.com/rxjs@5/bundles/Rx.min.js"></script>
答案 1 :(得分:0)
使用first()和repeat()的组合。如果$完成发射序列完成
//emit every 1s
const a$=new Rx.BehaviorSubject(0)
Rx.Observable.interval(1000).take(100).skip(1).subscribe(a$);
// //simulate aysnc
const async = (val)=>{
console.log('async start with:'+ val)
return Rx.Observable.timer(5100).mapTo('async done:'+val);
}
a$.first().switchMap(value=>async(value))
.repeat()
.catch(e=>Rx.Observable.empty())
.subscribe(console.log,console.err,console.warn)
a$.subscribe(console.warn)
答案 2 :(得分:0)
我用打字稿想出了这个解决方案:
我有一个简单的Gate
类,可以打开或关闭:
enum GateStatus {
open = "open",
closed = "closed"
}
class Gate {
private readonly gate$: BehaviorSubject<GateStatus>;
public readonly open$: Observable<GateStatus>;
public readonly closed$: Observable<GateStatus>;
constructor(initialState = GateStatus.open) {
this.gate$ = new BehaviorSubject<GateStatus>(initialState);
this.open$ = this.gate$
.asObservable()
.pipe(filter(status => status === GateStatus.open));
this.closed$ = this.gate$
.asObservable()
.pipe(filter(status => status === GateStatus.closed));
}
open() {
this.gate$.next(GateStatus.open);
}
close() {
this.gate$.next(GateStatus.closed);
}
}
运算符功能非常简单。开始时,大门是打开的。在开始请求之前,请先将其关闭,然后在请求完成后再次将其打开。
audit()
仅在门打开时才允许最新的请求数据通过。
export const requestThrottle = <T>(
requestHandlerFactory: (requestData: T) => Observable<any>
) => (requestData: Observable<T>) => {
const gate = new Gate();
return requestData.pipe(
audit(_ => gate.open$),
mergeMap(value => {
gate.close();
return requestHandlerFactory(value).pipe(finalize(() => gate.open()));
})
);
};
像这样使用它:
src.pipe(
requestThrottle(() => of(1).pipe(delay(100)))
);