首页 > 解决方案 > 如何使用 iif() 运算符正确实现条件 debounceTime() 运算符?

问题描述

我有一个BehaviourSubject通过构造函数中的 getSaveBehaviorSubject() 订阅的。这个 behaviorsubjectService可以从其他组件/服务接收多种类型的数据,其中一些类型需要存储在后端,而其他类型不需要。当它接收到需要存储的值时,它会通过put/post请求将其发送到后端。作为请求速率限制器,我正在使用debounce(300)运算符,以便在 300 毫秒不活动之后向服务器发出实际请求。这将防止服务器抛出429 Too many requests错误。仅当推送需要存储的值类型时才应应用 debounce 运算符。我试过用iif()操作员创造这样的条件。我的代码如下所示:

this.myService.getSaveBehaviorSubject()
.pipe(
  tap(pair => {
    if(this.dataStoreServiceJustInitialized){
      this.dataStoreServiceJustInitialized = false; 
      return;
    }

    if (pair.length > 1){
        this.updateDataTypeValue(pair);
        localStorage.setItem(pair[0], JSON.stringify(pair[1]));
        if(pair[0] === DataType.MEASURE_SYSTEM_PREFERENCE)
            this.adjustSearchRadiusToChangedMeasureSystem();
    }
  }),
  mergeMap(pair =>
    iif(() => !!(this.loggedInSubject.value && this.dataTypeExclusionList.includes(pair[0])), 
    of(pair).pipe(debounceTime(2000)), of(pair)
    )))
.subscribe(pair => {If (this.loggedInSubject.value) // make request to server...}

我的解决方案基于本教程:https ://www.learnrxjs.io/learn-rxjs/operators/conditional/iif并且感兴趣的代码从mergeMap.

如果用户已登录并且数据类型应该保存到数据库中(不包含在 中dataTypeExclusionList),那么iif()应该返回一个带有包含debounceTime操作符的管道的 observable。否则它应该只返回一个具有原始值的新 observable。

iif条件为真时,debounceTime 似乎不起作用。无论我是否登录或是否应该保存数据类型,它总是会立即发送请求。显然我做错了什么。

谁能告诉我将 iif 运算符与 debounceTime 运算符结合使用的正确方法是什么?谢谢

标签: angularrxjsrxjs6iif

解决方案


这里有两个问题:

  1. debounceTime将在其源完成时立即发出其当前值 - 无需等待超时。工厂将of生成一个通知,然后立即完成。因此,不会发生去抖动。您可以通过替换来解决此问题debounceTimedelay因为即使源已经完成,它也会等待发出。

  2. 您正在使用mergeMap,它不会在收到新通知时取消订阅之前的 Observable。因此,您可能会遇到在getSaveBehaviorSubject超时内发出 100 次并且您将发送 100 个服务器请求的情况。您可以通过替换为来解决此mergeMap问题switchMap

两者都应用应该可以解决您的问题。

但是,我会推荐一种不同的方法:利用debounce运算符。你传入一个返回 Observable 的函数,而不是超时值。当这个 Observable 发出时,当前值将被转发。

像这样:

this.myService.getSaveBehaviorSubject().pipe(
  tap(...),
  debounce(pair => {
    if(... debounce condition ...) {
      return timer(2000);
    } else {
      return timer(0);
    }
  }
}

推荐阅读