Throttling jest kolejnym sposobem na optymalizację aplikacji. Bardzo często throttling jest opisywany wraz z debounce (o którym pisałem tutaj – Debounce function), ponieważ oba te mechanizmy pozwalają na wywołanie funkcji, po wystąpieniu określonych warunków. O różnicach napiszę później, chociaż po przeczytaniu artykułów o throttling oraz debounce, wszystko powinno być jasne.
Jak działa throttling?
Korzystając z throttling możemy wywołać funkcję tylko raz, w określonym przez nas interwale czasowym.
Żeby lepiej zobrazować przypadek użycia, wyobraźmy sobie, że chcemy wywołać jakieś zdarzenie podczas ruchu myszką. Jeżeli wywołamy funkcję przy każdym ruchu, to w praktyce otrzymamy bardzo dużą liczbę wywołań funkcji. Do optymalizacji wywołań idealnie nadaje się throttling, co pokażę w poniższych przykładach.
Przejdźmy do przykładu…
Skorzystamy z create-react-app, a następnie z biblioteki lodash, dodając ją do projektu poprzez komendę:
npm i --save lodash
Przykład onMouseMove bez throttling
Nasz przypadek użycia będzie obejmował wyświetlenie w konsoli położenia kursora po ruchu myszką w ramach elementu <div>
class App extends React.Component { mouseMove = (event) => { console.log(new Date().toISOString(), ' clientX:', event.clientX, 'clientY:', event.clientY); } render() { return ( <div onMouseMove={this.mouseMove}> Example </div> ); } }
Jak widać w konsoli, liczba wywołań funkcji jest olbrzymia. Każdy najmniejszy ruch myszką powoduje wywołanie funkcji:
2020-12-20T16:40:28.490Z clientX: 38 clientY: 11 2020-12-20T16:40:28.497Z clientX: 55 clientY: 11 2020-12-20T16:40:28.504Z clientX: 68 clientY: 11 2020-12-20T16:40:28.512Z clientX: 78 clientY: 11 2020-12-20T16:40:28.520Z clientX: 84 clientY: 11
Przykład ten jest bardzo prosty, ale w sytuacji gdy wymagalibyśmy jakiś obliczeń i np. uderzenia do API, aby wysłać dany wynik, zwykłe onMouseMove bez dodatkowych ograniczeń, mogłoby się nie sprawdzić.
Skorzystajmy zatem z mechanizmu throttling, aby zoptymalizować liczbę wywołań.
Przykład onMouseMove z throttling
import {throttle} from 'lodash'; class App extends React.Component { constructor(props) { super(props); this.throttledMouseMove = throttle(this._mouseMove, 5000); } _mouseMove = (event) => { console.log(new Date().toISOString(), ' clientX:', event.clientX, 'clientY:', event.clientY); } render() { return ( <div onMouseMove={this.throttledMouseMove}> Example </div> ); } }
Co zmieniło się w komponencie? Przede wszystkim zaimportowaliśmy throttle
z biblioteki lodash
. Dodatkowo, w konstruktorze zdefiniowaliśmy obsługę mechanizmu throttle. Ustawienienia powodują wywołanie funkcji raz na 5 sekund (5000 ms).
this.throttledMouseMove = throttle(this._mouseMove, 5000);
Tym prostym sposobem ograniczyliśmy liczbę wywołań funkcji do jednej w ciągu 5 sekund (parametr).
Widać to też w konsoli, gdy nieustannie ruszamy myszką w ramach obszaru <div>
.
2020-12-20T16:17:23.721Z clientX: 60 clientY: 12 2020-12-20T16:17:28.724Z clientX: 37 clientY: 10 2020-12-20T16:17:33.724Z clientX: 19 clientY: 14 2020-12-20T16:17:38.765Z clientX: 65 clientY: 6 2020-12-20T16:17:43.765Z clientX: 108 clientY: 12
Throttling i debounce – różnice
Zmieńmy jeszcze wywołanie throttle
na debounce
i zobaczmy, jak teraz zachowuje się komponent.
import React from 'react'; import {debounce} from 'lodash'; class App extends React.Component { constructor(props) { super(props); this.debounceMouseMove = debounce(this._mouseMove, 5000); } _mouseMove = (event) => { console.log(new Date().toISOString(), ' clientX:', event.clientX, 'clientY:', event.clientY); } render() { return ( <div onMouseMove={this.debounceMouseMove}> Example </div> ); } }
Jak przetestować działanie? Wystarczy poruszać myszką przez kilkanaście sekund, następnie przerwać ruchy myszką. W ten sposób dopiero 5 sekund po zaprzestaniu ruchów myszką w konsoli otrzymamy wynik console.log()
. W skrócie, debounce
uruchamia się raz, X milisekund po zakończeniu zdarzenia. Throttle
z kolei uruchamia się raz, w ramach zdefiniowanego interwału czasowego. Myślę, że te proste przykłady pozwolą dobrać odpowiednie użycie funkcję w Waszych aplikacjach.
Źródła:
Obraz: https://unsplash.com/photos/RSsqjpezn6o
Lodash: https://www.npmjs.com/package/lodash
Create react app: https://pl.reactjs.org/docs/create-a-new-react-app.html