简体   繁体   English

RxSwift - 去抖动/油门“逆”

[英]RxSwift - Debounce/Throttle "inverse"

Let's say I have an instant messaging app that plays a beep sound every time a message arrives.假设我有一个即时消息应用程序,每次消息到达时都会播放哔声。 I want to debounce the beeps, but I'd like to play the beep sound for the first message arrived and not for the following ones (in a timespan of, say, 2 seconds).我想消除debounce哔声,但我想为到达的第一条消息播放哔哔声,而不是为以下消息播放哔声(例如,2 秒的时间跨度)。

Another example might be: my app sends typing notifications (so the user I'm chatting with can see that I'm typing a message).另一个示例可能是:我的应用程序发送输入通知(因此与我聊天的用户可以看到我正在输入消息)。 I want to send a typing notification when I start typing, but only send new ones in X-seconds intervals, so I don't send a typing notification for every character I type.我想在开始输入时发送输入通知,但仅以 X 秒为间隔发送新通知,因此我不会为我输入的每个字符发送输入通知。

Does this make sense?这有意义吗? Is there an operator for that?有运营商吗? Could it be achieved with the existing operators?现有的运营商能做到吗?

This is my code for the first example.这是我的第一个示例的代码。 I'm solving it now with debounce , but it's not ideal.我现在用debounce解决它,但这并不理想。 If I receive 1000 messages in intervals of 1 second, it won't play the sound until the last message arrives (I'd like to play the sound on the first one).如果我每隔 1 秒收到 1000 条消息,则在最后一条消息到达之前它不会播放声音(我想在第一条消息上播放声音)。

self.messagesHandler.messages
            .asObservable()
            .skip(1)
            .debounce(2, scheduler: MainScheduler.instance)
            .subscribeNext { [weak self] message in
                    self?.playMessageArrivedSound()
            }.addDisposableTo(self.disposeBag)

Thanks!谢谢!

Updated for RxSwift 3 and improved throttle operator针对 RxSwift 3 进行了更新并改进了throttle操作员

With new behavior of throttle operator, introduced in RxSwift 3.0.0-beta.1, you can use it just like that:随着 RxSwift 3.0.0-beta.1 中引入的throttle操作符的新行为,您可以像这样使用它:

    downloadButton.rx.tap
    .throttle(3, latest: false, scheduler: MainScheduler.instance)
    .subscribe(onNext: { _ in
        NSLog("tap")
    }).addDisposableTo(bag)

Old version of answer旧版答案

Use window operator and then transform Observable<Observable<Type>> to flat Observable using flatMap .使用window运算符,然后使用flatMapObservable<Observable<Type>>转换为平面Observable

This sample code prints 'tap' only for first tap in every 3 seconds windows (or if tap count exceeds 10000).此示例代码仅在每 3 秒窗口中的第一次点击时打印“点击”(或者如果点击计数超过 10000)。

    downloadButton.rx_tap
    .window(timeSpan: 3, count: 10000, scheduler: MainScheduler.instance)
    .flatMap({ observable -> Observable<Void> in
        return observable.take(1)
    })
    .subscribeNext { _ in
        NSLog("tap")
    }.addDisposableTo(bag)

Window is a great solution, but I find the sample operator more intuitive and also with correct behavior. Window 是一个很好的解决方案,但我发现示例运算符更直观且行为正确。

messagesHandler.messages
               .sample(Observable<Int>.timer(0.0, period: 2.0, scheduler: MainScheduler.instance))
               .subscribeNext { [weak self] message in
                    self?.playMessageArrivedSound()
               }.addDisposableTo(self.disposeBag)

The throttle operation does not do what I thought it should.油门操作没有做我认为应该做的事情。

For people that also find throttle is too confusing:对于那些也觉得油门太混乱的人:

"throttle will only forward an event once the source observable has stopped sending events for the specified period of time. This does not work well with regular event delivery" for more details . “只有当源 observable 在指定的时间段内停止发送事件时,节流才会转发事件。这不适用于常规事件传递”了解更多详细信息

In this case, the filter you want is在这种情况下,您想要的过滤器是

sample(Observable<Int>.timer(0.0, period: 2.0, scheduler: MainScheduler.instance))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM