3 Ways to Debounce HTTP Requests in Angular

栏目: IT技术 · 发布时间: 4年前

内容简介:Debouncing is the delay of a function/method execution or an action for a period of the specified time. During this specified time, calls to the method/function or action are collected and executes each one when the specified has elapsed.Suppose you have a

How to improve your Angular app’s performance with debouncing.

3 Ways to Debounce HTTP Requests in Angular

Image by Fran__ from Pixabay

Debouncing is the delay of a function/method execution or an action for a period of the specified time. During this specified time, calls to the method/function or action are collected and executes each one when the specified has elapsed.

Suppose you have a blog website with a search bar where users can search for posts. When a user types in the name of a blog to search in the search bar, an HTTP request is sent to the web API to search for blog post names or mentions with the search tokens.

You will find out that the server will always be called on every single letter typed. For example, you want articles based on “Javascript” and “optimization”, then you typed “Javascript optimization”. For every single letter in “Javascript optimization”, the server will be called, that means the server will be called 23 times(the number of letters in “Javascript optimization” plus the space) just to search for blog posts with “Javascript optimization” keywords and *ngFor will trigger change detection run on the component 10 times.

The code in Angular will look like this:

@Component({
    ...,
    template: `
        <input type="text" placeholder="Search" (keyup)="search(evt)"        <div *ngFor="let result of results$ | async">
            //...
        </div>
    `
})
class SearchBarComponent {
    results$: Observable    constructor(private httpClient: HttpClient) {}    search(evt) {
        const searchText = evt.target.value        this.results$ = this.httpClient.get("/api/search?q=" + searchText)
    }
}

See, we bound the keyup event to the input#text to call the search method whenever we type on the text input. The search method extracts the data typed in the input#textbox and performs an HTTP GET request to "/api/search/" via HttpClient, the result is assigned to results$ and is displayed on the DOM using *ngFor and async pipe.

Sending HTTP request for every keystroke could become very expensive. We have to delay the HTTP call to the server for a considerable amount of time before triggering a search for the currently typed word. This is called debouncing , it waits for a specified time before calling a function.

Let’s see the ways by which we can debounce the search method. First, is the use of the popular library RxJS operators: debounce and debounceTime.

Tip:as we all know, rewriting code is a recipe for bad code. Use tools like Bit ( Github ) to “harvest” reusable components from your codebase and share them on bit.dev . This way you and your team can easily find them, import them to any project and develop them further if needed. It’s a good way to guarantee high quality, scalable and maintainable code.

3 Ways to Debounce HTTP Requests in Angular
Example: searching for shared-component in bit.dev

1. Using RxJS

debounce

We will use RxJS debounce operator to delay calls to the search method

debounce emits a value form the source Observable only after a particular life span determined by another Observable has passed without another source emission.

@Component({
    ...,
    template: `
        <input type="text" placeholder="Search" (keyup)="search(evt)"        <div *ngFor="let result of results$ | async">
            //...
        </div>
    `
})
class SearchBarComponent implements OnInit {
    results$: Observable
    subject = new Subject()    constructor(private httpClient: HttpClient) {}    ngOnInit() {
        this.results$ = this.subject.pipe(
            debounce(() => Rx.Observable.interval(1000)),
            map(searchText => this.httpClient.get("/api/search?q=" + searchText))
        )
    }    search(evt) {
        const searchText = evt.target.value
        // emits the `searchText` into the stream. This will cause the operators in its pipe function (defined in the ngOnInit method) to be run. `debounce` runs and then `map`. If the time interval of 1 sec in debounce hasn't elapsed, map will not be called, thereby saving the server from being called.
        this.subject.next(searchText)
    }
}

We added a Subject (a type of Observable), this is to form a gateway in which the text search will pass before hitting the HttpClient. We used the pipe function in the Subject to add operators: debounce and map.

We set the debounce to be 1 sec (1000ms), debounce depends on external source Observable to set the time debounce would have to delay emission, we used the interval function to set the time. The map has a callback function that will perform the HTTP GET request to the server. With this, we have added a delay to our search mechanism.

debounceTime

We can write cleaner code with debounceTime , this operator doesn’t need time to be set by a source Observable, here we pass the time delay to the debounceTime operator.

@Component({
    ...,
    template: `
        <input type="text" placeholder="Search" (keyup)="search(evt)"        <div *ngFor="let result of results$ | async">
            //...
        </div>
    `
})
class SearchBarComponent implements OnInit {
    results$: Observable
    subject = new Subject()    constructor(private httpClient: HttpClient) {}    ngOnInit() {
        this.results$ = this.subject.pipe(
            debounceTime(1000),
            map(searchText => this.httpClient.get("/api/search?q=" + searchText))
        )
    }    search(evt) {
        const searchText = evt.target.value
        // emits the `searchText` into the stream. This will cause the operators in its pipe function (defined in the ngOnInit method) to be run. `debounceTime` runs and then `map`. If the time interval of 1 sec in debounceTime hasn’t elapsed, map will not be called, thereby saving the server from being called.
        this.subject.next(searchText)
    }
}

Same but simpler.

2. Using lodash/underscore debounce method

The lodash and underscore utility libraries export the debounce function that we can use to debounce methods/functions execution.

underscore

Let’s see how we can use the debounce in the underscore library to debounce our search function:

// ...
import * as _ from 'underscore';@Component({
    ...,
    template: `
        <input type="text" placeholder="Search" (keyup)="search(evt)"        <div *ngFor="let result of results$ | async">
            //...
        </div>
    `
})
class SearchBarComponent {
    results$: Observable    constructor(private httpClient: HttpClient) {
        this.search = _.debounce(this.search, 1000)
    }    search(evt) {
        const searchText = evt.target.value        this.results$ = this.httpClient.get("/api/search?q=" + searchText)
    }
}

We imported all the exported functions from underscore as _ . Then, in the constructor, we called the _.debounce function passing in our search method and delay time of 1 sec, and re-assigning the returned debounced-version of this.search to the search method. With this, the search method has become debounced, it will not call the server until 1 sec has elapsed.

Let’s repeat the same with lodash

lodash

// ...
import { debounce } from 'lodash';@Component({
    ...,
    template: `
        <input type="text" placeholder="Search" (keyup)="search(evt)"        <div *ngFor="let result of results$ | async">
            //...
        </div>
    `
})
class SearchBarComponent {
    results$: Observable    constructor(private httpClient: HttpClient) {
        this.search = debounce(this.search, 1000)
    }    search(evt) {
        const searchText = evt.target.value        this.results$ = this.httpClient.get("/api/search?q=" + searchText)
    }
}

Same as what we did using underscore.

3. Using decorators

We can leverage decorators to debounce methods in our Angular components. Angular already made heavy use of decorators, so using decorators for debouncing methods would not be off.

import { debounce } from 'lodash';/**
 * Debounce a method
 */
function Debounce(ms) {
  return function(target: any, key: any, descriptor: any) {
    const oldFunc = descriptor.value
    const newFunc = debounce(oldFunc, ms)
    descriptor.value = function() {
        return newFunc.apply(this, arguments)
    }
  }
}import * as _ from 'underscore';/**
 * Debounce a method
 */
function Debounce(ms) {
  return function(target: any, key: any, descriptor: any) {
    const oldFunc = descriptor.value
    const newFunc = _.debounce(oldFunc, ms)
    descriptor.value = function() {
        return newFunc.apply(this, arguments)
    }
  }
}

We can then decorate the search method with the Debounce decorator:

@Component({
    ...,
    template: `
        <input type="text" placeholder="Search" (keyup)="search(evt)"        <div *ngFor="let result of results$ | async">
            //...
        </div>
    `
})
class SearchBarComponent {
    results$: Observable    constructor(private httpClient: HttpClient) {
    }    @Debounce(1000)
    search(evt) {
        const searchText = evt.target.value        this.results$ = this.httpClient.get("/api/search?q=" + searchText)
    }
}

Simple

Conclusion

We have seen ways by which we can debounce or delay HTTP requests in an Angular app. RxJS, lodash and underscore libraries provide a great and safe way we can use to prevent unwanted HTTP requests from our Angular app.

Delaying HTTP requests shuts out unnecessary server requests, preventing a function/method/action both client- and server-side from being called over and over rapidly.

If you have any questions regarding this or anything I should add, correct or remove, feel free to comment, email or DM me.

Thanks !!!


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

C++程序设计

C++程序设计

谭浩强 / 清华大学出版社 / 2004-6-1 / 36.00元

《C++程序设计》作者深入调查了我国大学的程序设计课程的现状和发展趋势,参阅了国内外数十种有关C++的教材,认真分析了学习者在学习过程中遇到的困难,研究了初学者的认识规律。在本书中做到准确定位,合理取舍内容,设计了读者易于学习的教材体系,并且以通俗易懂的语言化解了许多复杂的概念,大大减少了初学者学习C++的困难。C++是近年来国内外广泛使用的现代计算机语言,它既支持面向过程的程序设计,也支持基于对......一起来看看 《C++程序设计》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

SHA 加密
SHA 加密

SHA 加密工具