比方说,我们有一些object TypeClassTest {
trait X
trait Y[T] {
def t: T
}
// Class with "static" method `t`
class Z extends X
// "static" method defined
implicit object Z extends Y[String] {
override def t = "t"
}
// Using 'static' method of the generic type
class A[T <: X : Y](underlying: T) {
val t: T = implicitly[Y[T]].t
}
}
可观察到并发出var values = new Array();
$('.selectList select').on('change', function(){
values = new Array();
$('.selectList select').find(":selected").each(function(){
values.push($(this).text());
});
console.log(values);
});
:
input$
对于每个发射,我需要切换到另一个可观察到的(类似于Item
)。但是,我需要确保所有这些可切换的观测值均完整且按顺序运行。足够容易地,我们有const input$: Observable<Item>;
可以做到这一点:
switchMap
但是,我想做的是:缓冲项目并减少它们(即,我有一个函数concatMap
),同时这些可切换的可观察对象之一处于活动状态。更具体地说,假设input$.pipe(concatMap(item => processItem(item)))
。在这种情况下,我的减速器就是(a: Item, b: Item): Item
。
我们有很多type Item = {[key: string]: string}
,{...a, ...b}
和buffer*
运算符可用,尽管我似乎找不到实现这种行为的 easy 组合
我可以很好地编写我的自定义运算符,但是我对是否可以将其表示为一些内置运算符的(简单的)组合感兴趣?
>仅需说明一下:可观察的输出应该发出我们切换到的可观察的值,而不是缓冲/减少的值。另外,尽管源的完成/错误应反映在输出中,但任何正在进行的内部订阅都应首先完成。
我要查找的运算符应该基本上具有类似于
的签名window*
为了完整性起见,这是我要寻找的操作员的大理石图。假定加法器为减速器,我们只是切换到输入,但要延迟四个刻度:
throttle*
在这里,bufferedConcatMap<T, R>(
project: (value: T) => Observable<R>,
reducer: (values: T[]) => T
): OperatorFunction<T, R>;
立即切换到我们的延迟(因为没有正在进行的内部订阅),并且在四个滴答声之后我们得到了结果。由于与此同时,Input: ---123--|
Output: ------1--(5|)
和1
都已发出,因此它们被缓冲在一起并减小到2
,这又在以后发出了四个滴答,因为我们仅在{之后{1}}已经回来。
答案 0 :(得分:0)
更新12/13 :由于我的操作假设是内置运算符的简单组合无法在此处完成工作,因此我实现了自己的运算符。与我的原始要求相反,它的行为如下:
concatMap
和exhaustMap
之类的运算符。我还没有为此编写测试套件,但是到目前为止看来还不错。
我将在此处you can also find a Stackblitz playground here中发布操作员的代码。
type Reducer<A, B> = (values: A[]) => B;
type Project<A, B> = (value: A) => ObservableInput<B>;
export function bufferReduceMap<A, B, R>(reducer: Reducer<A, B>, project: Project<B, R>): OperatorFunction<A, R> {
return function (source: Observable<A>) {
return source.lift(new BufferReduceMapOperator<A, B, R>(reducer, project));
};
}
class BufferReduceMapOperator<A, B, R> implements Operator<A, R> {
constructor(private reducer: Reducer<A, B>, private project: Project<B, R>) {}
call(subscriber: Subscriber<R>, source: any): TeardownLogic {
return source.subscribe(new BufferReduceMapSubscriber<A, B, R>(subscriber, this.reducer, this.project));
}
}
class BufferReduceMapSubscriber<A, B, R> extends OuterSubscriber<A, B> {
private buffer: A[] = [];
private active = false;
private hasCompleted = false;
private hasErrored = false;
constructor(
destination: Subscriber<R>,
private reducer: Reducer<A, B>,
private project: Project<B, R>,
) {
super(destination);
}
protected _next(value: A) {
const buffer = this.buffer;
buffer.push(value);
this._tryNext();
}
protected _complete() {
this.hasCompleted = true;
if (!this.active && this.buffer.length === 0) {
this.destination.complete();
}
this.unsubscribe();
}
public notifyComplete(innerSub: Subscription) {
this.remove(innerSub);
this.active = false;
if (this.buffer.length !== 0) {
this._tryNext();
} else if (this.hasCompleted) {
this.destination.complete();
}
}
protected _tryNext() {
if (this.active) {
return;
}
let reduced: B;
try {
reduced = this.reducer(this.buffer);
} catch (err) {
this.destination.error(err);
return;
}
let result: ObservableInput<R>;
try {
result = this.project(reduced);
} catch (err) {
this.destination.error(err);
return;
}
this.active = true;
const innerSubscriber = new InnerSubscriber(this, undefined, undefined);
const destination = this.destination as Subscription;
destination.add(innerSubscriber);
this.buffer = [];
subscribeTo<R>(result)(innerSubscriber);
}
}