我对元素输入事件进行了简单的反跳,如下所示:
Observable
.fromEvent(this.elInput.nativeElement, 'input')
.debounceTime(2000)
.subscribe(event => this.onInput(event));
我想根据事件发生时的值来设置防抖条件,这可能吗?
谢谢
答案 0 :(得分:3)
是的,那是完全可能的。只需使用 input {
beats {
port => 5044
}
}
output {
elasticsearch {
hosts => "localhost:9200"
manage_template => false
index => "%{[@metadata][beat]}-%{[@metadata][version]}-%{+YYYY.MM.dd}"
} stdout {
codec => rubydebug { metadata => true }
}
}
运算符而不是debounce
。传递给选择器函数,该函数在调用时会收到先前的运算符通知。
在您的示例中:
debounceTime
选择器函数需要一个Observable
.fromEvent(this.elInput.nativeElement, 'input')
.debounce(ev => ev.hasSomeValue ? timer(2000) : EMPTY)
.subscribe(event => this.onInput(event));
并等待其发出,然后转发ObservableLike
收到的最后一个通知。与debounce
一样,所有其他通知也将被丢弃。您可以使用debounceTime
立即转发通知,而不会超时(尽管这将是异步的,请参见下文)
来自learn-rxjs:
尽管反跳时间没有广泛使用,但是当反跳速率可变时,反跳很重要!
注意:,即使内部Observable立刻发出信号,防抖动也会始终异步安排最后一个值的转发。为避免这种情况,您必须创建第二个可观察对象,并使用EMPTY
来完全避免filter
。
答案 1 :(得分:2)
如果管道不处理任何变量,则上一个答案有效。加上将0和asap传递给debounceTime(因此:debounceTime(0, asap)
)确实意味着将立即调用下一个运算符。实际上,一旦您使用debounceTime,您可能会遇到半秒的延迟,这在某些情况下会太长。
因此,在长时间与iif
和朋友搞混之后,我决定复制粘贴debounceTime并将其修改为具有条件功能。任何想法/改进都是最欢迎的:
这是针对Angular 9的,可能会在以前的版本中引发警告/错误。
就像使用debounceTime一样使用它,只需将条件函数作为第一个布尔参数即可。如果为true,它将反跳,如果为false,它将立即继续。
示例:
observable$.pipe(
conditionalDebounceTime(() => conditionFlag, 1000),
tap(observedValue ... => ...)
...
conditional-debounce-time.ts
import {MonoTypeOperatorFunction, Observable, Operator, SchedulerLike, Subscriber, Subscription, TeardownLogic} from 'rxjs';
import {async} from 'rxjs/internal/scheduler/async';
class ConditionalDebounceTimeSubscriber<T> extends Subscriber<T> {
private debouncedSubscription: Subscription|null = null;
private lastValue: T|null = null;
private hasValue = false;
constructor(destination: Subscriber<T>,
private conditionFunc: () => boolean,
private dueTime: number,
private scheduler: SchedulerLike) {
super(destination);
}
protected _next(value: T) {
this.clearDebounce();
this.lastValue = value;
this.hasValue = true;
if (this.conditionFunc()) {
this.add(this.debouncedSubscription = this.scheduler.schedule(dispatchNext, this.dueTime, this));
} else {
(<Subscriber<T>>this.destination).next(this.lastValue);
}
}
protected _complete() {
this.debouncedNext();
(<Subscriber<T>>this.destination)!.complete();
}
debouncedNext(): void {
this.clearDebounce();
if (this.hasValue) {
const { lastValue } = this;
// This must be done *before* passing the value
// along to the destination because it's possible for
// the value to synchronously re-enter this operator
// recursively when scheduled with things like
// VirtualScheduler/TestScheduler.
this.lastValue = null;
this.hasValue = false;
(<Subscriber<T>>this.destination)!.next(lastValue!);
}
}
private clearDebounce(): void {
const debouncedSubscription = this.debouncedSubscription;
if (debouncedSubscription !== null) {
this.remove(debouncedSubscription);
debouncedSubscription.unsubscribe();
this.debouncedSubscription = null;
}
}
}
class ConditionalDebounceTime<T> implements Operator<T, T> {
constructor(private conditionFunc: () => boolean, private dueTime: number, private scheduler: SchedulerLike) {
}
call(subscriber: Subscriber<T>, source: any): TeardownLogic {
return source.subscribe(new ConditionalDebounceTimeSubscriber(subscriber, this.conditionFunc, this.dueTime, this.scheduler));
}
}
export function conditionalDebounceTime<T>(conditionFunc: () => boolean, dueTime: number, scheduler: SchedulerLike = async): MonoTypeOperatorFunction<T> {
return (source: Observable<T>) => source.lift(new ConditionalDebounceTime(conditionFunc, dueTime, scheduler));
}
function dispatchNext(subscriber: ConditionalDebounceTimeSubscriber<any>) {
subscriber.debouncedNext();
}