【问题标题】:Debouncing HTTP requests in Angular在 Angular 中反跳 HTTP 请求
【发布时间】:2017-06-21 20:47:01
【问题描述】:

我在 Angular 2 中构建了一个加载微调器组件,我想在发出 http 请求之前触发它,并在它们完成时禁用它。问题是每次用户更改输入(检查框,输入输入框)时,都会触发 http 请求。这意味着很多请求,并且覆盖层不断出现。我想在触发输入后等待一段时间(半秒?),然后再触发 http 请求,让用户有时间输入其他输入。我已经阅读了一些关于 debounce 的内容,但据我所知,这是在发出另一个请求之前等待的时间吗?据我所知,这只是请求之间的缓冲时间。

基本上,现在,我有一个组件来处理我的输入。当输入改变时(现在是复选框),会触发以下代码:

@Output() filtersChanged = new EventEmitter();
emitFilters(): void {
    this.filtersChanged.emit(this.filters);
}

通过中间步骤触发我的 http 请求:

getEvents(filters): Observable<Event[]> {
    this.loadingSpinnerService.showLoadingSpinner();
    let params: URLSearchParams = new URLSearchParams();
    params.set('types', filters.types.join(','));
    params.set('dates', filters.dates.join(','));
    return this.http
        .get('//api.dexcon.local/getEvents.php', { search: params })
        .map((response: Response) => {
            return response.json().events;
        });
}

在 Angular 1 中,我会将其置于每次用户影响输入时刷新的超时,因此它会在最终输入被触摸后触发设定的时间。这也是 Angular 2 中最好的方法吗?根据我的阅读,去抖动会阻止请求发生得太接近第二个请求,但我想知道如何最好地防止在给定时间段内采取行动后发生请求。

【问题讨论】:

  • 请发布代码,展示您尝试完成的工作、尝试的工作以及失败的地方。
  • 我没有特定于节流的代码,我在询问理论,它应该如何完成。我还没有编写代码,因为我无法弄清楚这里适合什么方法。我应该从我的 Angular 1 代码中显示设置的超时功能吗?还是我应该只使用 Angular 2 提供到目前为止的代码?
  • SO 问题应该证明您的努力。也许stackoverflow.com/questions/32051273/angular2-and-debounce
  • 我会提交我的代码,尽管我已经看到并使用了大量的 SO 问题,这些问题没有显示代码,并且只是关于正确/错误的做事方式,所以我没有自己问一个人觉得很奇怪。我之前看到过这个问题,但它并没有真正解决我想要做的事情,除非我也不明白它做了什么。我可以展示我现在拥有的代码,但我无法展示我搜索的努力并且无法理解如何做到这一点?
  • 当然有很多平庸或糟糕的问题。他们中的许多人没有得到好的答案是有充分理由的;-)

标签: angular


【解决方案1】:

完成你所追求的最简单的方法是设置一个主题(我假设你在这里可以访问 Rxjs)。在您的组件中初始化一个:

inputSubject: Subject<string> = new Subject<string>();

由于 Subject 既是观察者又是可观察者,因此您需要设置订阅来监听变化。您可以在此处应用去抖动功能。

this.subscription = this.inputSubject.asObservable()
    .debounceTime(1000)
    .subscribe(x => this.filtersChanged.emit(this.filters));

现在,在您的 emitFilters() 函数中,而不是直接发射,将值推送到主题上。

this.inputSubject.next(newValue);

不要忘记将订阅存储为组件类的成员,并在 OnDestroy() 中正确处理它。

ngOnDestroy() {
    if (this.subscription) {
      this.subscription.unsubscribe();
    }
}

【讨论】:

  • @RhoVisions 对这是否适合您的方案有任何想法吗?
  • 我考虑过 observables,但我不确定,主要是因为我可能不了解 debounce 是如何工作的?它是“等待”,还是推动之间的休息?我希望做的是当用户点击输入时,等待 x 时间,如果点击另一个输入,刷新 x 计时器,如果没有,则执行操作。这有意义吗?
  • 经过测试,虽然我还有很多东西要弄清楚/学习,但它确实有效。
  • 您所描述的正是 debounce 在场景下的作用。如果您要使用 Angular 2,我绝对建议您使用 Observables 和 Rxjs,它们可以完美地结合在一起。这是另一个直接利用 Angular 2 食谱中的主题通过中介服务实现最佳组件交互的示例:angular.io/docs/ts/latest/cookbook/…
  • 谢谢。我发现自己并不害怕 Observables,它们确实非常有用,我只是发现文档不够出色,而且很少有易于理解的示例。感谢您的说明。
【解决方案2】:

您应该能够通过使用 debounce 函数装饰您的 getEvents 方法来解决此问题:

    function debounce(ms: number) {

        let timeoutId;

        return function (target: Object, propName: string, descriptor: TypedPropertyDescriptor<any>) {
            let originalMethod = descriptor.value;
            descriptor.value = function (...args: any[]) {
                if (timeoutId) return;
                timeoutId = window.setTimeout(() => {
                    timeoutId = null;
                }, ms);
                return originalMethod.apply(this, args);
            }
        }
    }

然后像这样简单地将它应用到你的方法中(将装饰器参数设置为你想要的去抖动时间,以毫秒为单位):

@debounce(300)
getEvents(filters): Observable < Event[] > {
    ...
}

【讨论】:

  • 我认为返回需要在超​​时之内。
  • 乍一看,很容易就这么认为。而且我认为我可以将代码编写得更简洁一些。但是,根据我的意图,它实际上是正确的。调用修饰函数(在本例中为 getEvents)将运行并返回 getEvents 的结果。如果下一次调用 getEvents 在 ms 定义的时间范围内,那么它将返回 void。基本上,这取决于您想要的功能。可以将 apply 语句放在超时内,但按照我的做法,去抖动时间内的任何调用都将被忽略,而不是稍后触发。
猜你喜欢
  • 2021-08-02
  • 2016-09-18
  • 2018-11-13
  • 2019-07-04
  • 1970-01-01
  • 1970-01-01
  • 2017-11-07
  • 2018-03-30
  • 2015-12-31
相关资源
最近更新 更多