[英]Debouncing HTTP requests in Angular
I've built a loading spinner component in Angular 2 that I'd like to trigger before http requests are made and disable when they're done.我已经在 Angular 2 中构建了一个加载微调组件,我想在发出 http 请求之前触发它,并在请求完成后禁用它。 The problem is that each time the user changes an input (checks of of a box, types into the input box), the http request fires.问题是每次用户更改输入(检查框,在输入框中键入)时,都会触发 http 请求。 This means a lot of requests, and the overlay is coming up constantly.这意味着很多请求,并且覆盖层不断出现。 I'd like to wait a set period of time (half a second?) after an input is triggered before triggering the http request, giving the user time to put in other inputs.我想在触发输入之后等待一段时间(半秒?),然后再触发 http 请求,让用户有时间输入其他输入。 I've read up a bit on debounce, but as far as I can see, that's for time waiting before making another request?我已经阅读了一些关于 debounce 的内容,但据我所知,这是在发出另一个请求之前等待的时间? And as far as I can see, that's just a buffer time between requests.据我所知,这只是请求之间的缓冲时间。
Basically, right now, I have a component that handles my inputs.基本上,现在,我有一个组件来处理我的输入。 When an input is changed (checkboxes right now), the following code is triggered:当输入更改时(现在是复选框),将触发以下代码:
@Output() filtersChanged = new EventEmitter();
emitFilters(): void {
this.filtersChanged.emit(this.filters);
}
Which through an intermediary step, sets off my http request:通过一个中间步骤,触发了我的 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;
});
}
In Angular 1, I would have put it in a timeout which refreshed each time a user affected an input, so it'd trigger a set time after the final input was touched.在 Angular 1 中,我会将其置于每次用户影响输入时刷新的超时中,因此它会在触摸最终输入后触发设定的时间。 Is this the best way to do it in Angular 2 as well?这也是在 Angular 2 中做到这一点的最佳方式吗? From my reading, debounce locks out a request from happening too close to a second request, but I'm wondering how to best prevent a request from happening after an action is taken for a given period of time.根据我的阅读,去抖动锁定了一个请求,使其不会发生太接近第二个请求,但我想知道如何最好地防止在给定时间段内采取操作后发生请求。
The easiest way to accomplish what you're after is to set up a Subject (I'm assuming you have access to Rxjs here).完成你所追求的最简单的方法是设置一个主题(我假设你可以在这里访问 Rxjs)。 Initialize one in your component:在您的组件中初始化一个:
inputSubject: Subject<string> = new Subject<string>();
Since a Subject is both an observer and an observable, you're going to want to set up a subscription to listen for changes.由于 Subject 既是观察者又是可观察者,因此您需要设置订阅以监听更改。 Here's where you can apply your debounce.您可以在此处应用去抖动。
this.subscription = this.inputSubject.asObservable()
.debounceTime(1000)
.subscribe(x => this.filtersChanged.emit(this.filters));
Now, in your emitFilters() function instead of directly emitting, push the value onto the Subject.现在,在您的 emitFilters() 函数中,而不是直接发射,将值推送到主题上。
this.inputSubject.next(newValue);
Don't forget to store your subscription as a member of your component class and dispose of it properly in your OnDestroy().不要忘记将订阅存储为组件类的成员,并在 OnDestroy() 中正确处理它。
ngOnDestroy() {
if (this.subscription) {
this.subscription.unsubscribe();
}
}
You should be able to solve this by decorating your getEvents method with a debounce function:您应该能够通过使用 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);
}
}
}
And then simply apply it to your method like this (set the decorator parameter to your desired debounce time in ms):然后像这样简单地将它应用到你的方法中(将装饰器参数设置为你想要的去抖动时间,以毫秒为单位):
@debounce(300)
getEvents(filters): Observable < Event[] > {
...
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.