根据条件去抖 rx 可观察 - RxSwift

Posted

技术标签:

【中文标题】根据条件去抖 rx 可观察 - RxSwift【英文标题】:Debounce rx observable based on condition - RxSwift 【发布时间】:2019-01-06 13:23:38 【问题描述】:

我在 Kotlin 中使用它来根据条件去抖动:

// variables
private val subject_isUpdating = PublishSubject.create<Int>()
var lastClickedItem = -1


// inside onCreate
adapter_cartProducts.setOnItemClickedListener  position ->
     subject_isUpdating.onNext(position)



// subscribing 
        subject_isUpdating
            .debounce
             position ->
                // here if lastClickedItem changed, no debounce
                if(position != lastClickedItem) 
                    lastClickedItem = position
                    Observable.empty()
                
                // else if same item clicked -> debounce
                else Observable.timer(300, TimeUnit.MILLISECONDS) 
            .subscribe( position ->
                updateOnWS(position, adapter_cartProducts.items[position])
            ,  error ->
                Timber.e(error) // printing the error
            )

这是从 RxJava 中使用的去抖选择器函数:

/**
 * Returns an Observable that mirrors the source ObservableSource, except that it drops items emitted by the
 * source ObservableSource that are followed by another item within a computed debounce duration.
 * <p>
 * <img   src="https://raw.github.com/wiki/ReactiveX/RxJava/images/rx-operators/debounce.f.png" >
 * <dl>
 *  <dt><b>Scheduler:</b></dt>
 *  <dd>This version of @code debounce does not operate by default on a particular @link Scheduler.</dd>
 * </dl>
 *
 * @param <U>
 *            the debounce value type (ignored)
 * @param debounceSelector
 *            function to retrieve a sequence that indicates the throttle duration for each item
 * @return an Observable that omits items emitted by the source ObservableSource that are followed by another item
 *         within a computed debounce duration
 * @see <a href="http://reactivex.io/documentation/operators/debounce.html">ReactiveX operators documentation: Debounce</a>
 */
public final <U> Observable<T> debounce(Function<? super T, ? extends ObservableSource<U>> debounceSelector) 
    ObjectHelper.requireNonNull(debounceSelector, "debounceSelector is null");
    return RxJavaPlugins.onAssembly(new ObservableDebounce<T, U>(this, debounceSelector));

这段代码的思想是,用户点击列表中的某一项,当用户停止点击400ms或点击另一个项目时,该项目将在webservice上更新

这可以在 RxSwift 中完成吗?

【问题讨论】:

【参考方案1】:

我不能说我特别喜欢你提供的代码,因为它依赖于外部变量。

这是一个可以做你想做的事情的运算符:

extension ObservableType where E: Equatable 

    func throttleUnlessChanged(_ dueTime: TimeInterval, scheduler: SchedulerType) -> Observable<E> 
        return Observable.create  observer in
            let lock = NSRecursiveLock()
            var last: E?
            var lastTime: RxTime?
            return self.subscribe  event in
                lock.lock(); defer  lock.unlock() 
                switch event 
                case .next(let element):
                    let now = scheduler.now
                    let timeIntervalSinceLast = lastTime != nil ? now.timeIntervalSince(lastTime!) : dueTime
                    if element != last 
                        observer.onNext(element)
                        last = element
                        lastTime = now
                    
                    else if timeIntervalSinceLast >= dueTime 
                        observer.onNext(element)
                        last = element
                        lastTime = now
                    
                case .error(let error):
                    observer.onError(error)
                case .completed:
                    observer.onCompleted()
                
            
        
    

这里有一个完整的测试要点:https://gist.github.com/dtartaglia/f5b041facfdcdd64630e0cb8cfc2cc5b

【讨论】:

很抱歉没有解释外部变量。我编辑了这个问题。你能再检查一下吗? 我很确定运营商会按照您的意愿行事。查看测试套件。你不解释外部变量我没有问题,我根本就存在它的问题。我不喜欢这样的块内的外部/未包含的副作用。我更新了要点中的运算符,以便使用 scan 而不是 create 实现它。 我只有一个问题,你写了 throttleUnlessChanged,它的行为会像 debounce 吗?因为我在这里想要的是 debounceUnlessChanged 我不完全确定在这种情况下有什么区别。在 RxSwift 中,debounce 已经在时间段结束时发出了最新的位置。在 RxSwift slack 上给我发一个 PM(或者只是在那里问),我或其他人可以根据您的规格帮助您使用自定义运算符。 slack.rxswift.org

以上是关于根据条件去抖 rx 可观察 - RxSwift的主要内容,如果未能解决你的问题,请参考以下文章

Rx scan(),无法从种子和另一个可观察对象生成可观察对象

一个可作为 ReplaySubject 但仅适用于第一个订阅者的 Rx 可观察对象?

RxSwift 可观察到的错误停止链 - 带有 Rx 的 Web 服务,如何恢复?

Rx 键值观察KVO的使用

重新组织链式可观察对象

响应式编程(Reactive Programming)(Rx)介绍