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 !!!


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

查看所有标签

猜你喜欢:

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

Web渗透技术及实战案例解析

Web渗透技术及实战案例解析

陈小兵 / 范渊、孙立伟 / 电子工业出版社 / 2012-4 / 89.00元

《Web渗透技术及实战案例解析》从Web渗透的专业角度,结合网络安全中的实际案例,图文并茂地再现Web渗透的精彩过程。《Web渗透技术及实战案例解析》共分7章,由浅入深地介绍和分析了目前网络流行的Web渗透攻击方法和手段,并结合作者多年的网络安全实践经验给出了相对应的安全防范措施,对一些经典案例还给出了经验总结和技巧,通过阅读《Web渗透技术及实战案例解析》可以快速掌握目前Web渗透的主流技术。《......一起来看看 《Web渗透技术及实战案例解析》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具