concept

Throttle (throttle)

A function can only be executed once at any given time.

Debounce (offer)

If an event is triggered within n seconds, the execution time of the function is recalculated.

The source code to learn

The realization of the throttle

function throttle(delay, callback) {
  let timeoutID;
  let lastExec = 0;
​
  function wrapper() {
    const self = this;
    const elapsed = Number(new Date()) - lastExec;
    const args = arguments;
​
    function exec() {
      lastExec = Number(new Date());
      callback.apply(self, args);
    }
​
    clearTimeout(timeoutID);
​
    if (elapsed > delay) {
      exec();
    } else {
      timeoutID = setTimeout(exec, delay - elapsed); }}return wrapper;
}
Copy the code

The whole code logic is very clear, there are only three steps:

  1. Calculates the elapsed time since the last function executionelapsedAnd clears the timer previously set.
  2. If the elapsed time is greater than the set intervaldelayExecute the function immediately and update the last time the function was executed.
  3. If the elapsed time is smaller than the set intervaldelay, then throughsetTimeoutSet a counter so that the function is indelay - elapsedTime to execute.

The source code is not hard to understand, but take a look at the use of this:

function throttle(delay, callback) { // ... function wrapper() { const self = this; const args = arguments; / /... function exec() { // ... callback.apply(self, args); }}}Copy the code

In the above code, the value of this is temporarily saved by the self variable and the correct value of this is passed in the exec function via callback.apply(self, args), a common practice in closures related function calls. Because of the handling of this, we can implement the following capabilities:

function foo() { console.log(this.name);  }
​
const fooWithName = throttle(200, foo);
​
const obj = {name: 'elvin'};
​
fooWithName.call(obj, 'elvin');
​
// => 'elvin'
Copy the code

Debounce implementation

Debouncen is easier to implement because it simply delays the execution of functions and does not throttle them at regular intervals:

function debounce(delay, callback) {
  let timeoutID;
​
  function wrapper() {
    const self = this;
    const args = arguments;
​
    function exec() {
      callback.apply(self, args);
    }
​
    clearTimeout(timeoutID);
​
    timeoutID = setTimeout(exec, delay);
  }
​
  return wrapper;
}
Copy the code

Comparing this code to the one you are implementing with Throttle, you can see that it is the code with the elapsed logic removed, and most of the rest is exactly the same, So the debounce function can be implemented with the help of throttle-debounce (which is also done in the source code), and the throttle function can be implemented with the help of debounce.

Application Scenario Example

Throttle and Debounce are applicable to scenarios where the user frequently performs the same operation within a short period of time, for example:

  • Trigger when the user drags the browser window to resize the windowresizeEvents.
  • The user moves the mouse, triggeringmousemoveSuch events.
  • The user enters the input in the input box, triggeringkeydown | keypress | keyinput | keyupSuch events.
  • The user scrolls the screen, triggeringscrollEvents.
  • After the user clicks the button, the API request takes time and the response is not immediately displayed. Therefore, the user may click the button repeatedlyclickEvents.

use

import { throttle } from 'throttle-debounce'
this.scrollThrottle = throttle(300, this.mainScroll)
Copy the code

To be perfect

IOS version of the implementation.

reference

  1. zhuanlan.zhihu.com/p/43410181
  2. www.runoob.com/w3cnote/js-…
  3. Demo.nimius.net/debounce_th…