Five steps of user-defined anti shake function to meet complex requirements

Posted by warstormer on Sun, 06 Feb 2022 20:00:38 +0100

Anti shake definition

Some frequently operated events will affect performance. "Anti shake" can be used to reduce the response frequency of events. When an event is triggered, the corresponding function will not be triggered immediately, but will wait. The response function will not be executed until the event stops triggering after waiting for a period of time.

Anti shake case

For example, the screen is set to turn off the screen for one minute. If the user does not operate the computer within this one minute, the computer will turn off the screen on time at one minute. However, if the user moves the mouse at the 50th second, the time of turning off the screen will be re timed from this moment, The screen will continue to turn off when there is no operation for 1 minute.

Anti shake usage scenario

In the process of programming, anti shake can be used in many scenes.

  • Frequent input and search in the input box
  • Click the button frequently and submit information to trigger an event
  • Listen for browser scrolling events
  • Listen for browser zoom events

When anti shake is not used

Here, a commodity search box is simulated. We need to call the interface for association query on the content entered by the user to give the user search tips.
When anti shake is not used, we will directly bind the function to the corresponding event.

// html code
<input>

// js code
const inputEl = document.querySelector('input')

let count = 0
const inputChange = function(){
    console.log(`The first ${++count}Call times inputChange method`)
}
inputEl.oninput = inputChange

Enter "javascript" in the input box, a total of 10 characters, so the method was called 10 times

The performance of this method is very low. First, it calls the interface every time you enter a character, causing great pressure on the server. Second, it is because the user does not stop inputting until the 10th character, and the complete information entered by the user is obtained at this time. The call of the first nine characters is not so necessary. Then, the function of "anti shake" is to wait until the user stops inputting, To execute the function, avoiding the waste of resources caused by multiple executions.

Self determined anti shake function

The implementation principle of anti shake function is to pass in the function to be executed and the delay time. After a series of processing, execute the incoming function.

Step 1: implementation of basic anti shake

Defines the execution time of the setTimeout delay function. clearTimeout is used to clear the timer and create a new timer when the next character has not been input for more than 1 second. If it has not been cleared, it is equivalent to calling the method every 1 s.

const debounce = function (fn, delay) {
  let timer = null;
  const _debounce = function () {
    if (timer) clearTimeout(timer);
    timer = setTimeout(()=>{
      fn()
    }, delay);
  };
  return _debounce;
};
inputEl.oninput = debounce(inputChange, 1000);

We hope that when the user completes the input, the function will be executed again, that is, it will be called only after 10 characters are input

But at this time, it is found that event target. Value is used to get the value entered by the user and becomes undefined

Step 2: expand this and parameters

When defining the function in the previous step, this object and event parameters were lost. To find them here, you only need to change the execution of this through call/apply/bind and pass in parameters when executing fn function.

const debounce = function (fn, delay) {
  let timer = null;
  const _debounce = function (...args) {
    if (timer) clearTimeout(timer);
    timer = setTimeout(()=>{
      fn.apply(this,args)
    }, delay);
  };
  return _debounce;
};
inputEl.oninput = debounce(inputChange, 1000);

In this way, we can get the user's input~

So far, most usage scenarios of anti shake have been implemented. Let's take a look at more complex requirements~

Step 3: the function executes immediately

In the anti shake function defined above, it is not executed immediately, that is, when the first character "j" is input, the function will not be called. There may be some scenarios. When the user completes the input, the call seems to respond slowly, so it needs to be called once when the first character is input.
Here, you can add a parameter to the incoming function to indicate whether it needs to be executed immediately. It is not required by default and is false. A variable is used in the function to save whether it needs to be executed for the first time. When the first execution is completed, set this variable to false

 const debounce = function (fn, delay, isImmediate = false) {
  let timer = null;
  let isExcute = isImmediate;
  const _debounce = function (...args) {
    if (isExcute) {
      fn.apply(this, args);
      isExcute = false;
    }
    if (timer) {
      clearTimeout(timer);
    }
    timer = setTimeout(() => {
      fn.apply(this, args);
      isExcute = isImmediate;
    }, delay);
  };
  return _debounce;
};

inputEl.oninput = debounce(inputChange, 1000, true);

It is called immediately when the character "j" is entered and once when the user input is completed, so there will be two calls here.

Step 4: cancel the function

Take a closer look. Our anti shake function can't be cancelled. It will be executed as long as it's time. In case the user hasn't finished inputting the content for one second, but he has closed the window, considering this situation, we have to arrange the cancellation function!
A function is also an object. We can bind another function to the function object in return_ Bind a cancel method to debounce, and execute the cancel method when it needs to be cancelled

// html
<button>cancel</button>

// javascript
const cancelBtn = document.querySelector("button");
const debounce = function (fn, delay, isImmediate = false) {
  let timer = null;
  let isExcute = isImmediate;
  const _debounce = function (...args) {
    if (isExcute) {
      fn.apply(this, args);
      isExcute = false;
    }
    if (timer) {
      clearTimeout(timer);
    }
    timer = setTimeout(() => {
      fn.apply(this, args);
      isExcute = isImmediate;
    }, delay);
  };
  _debounce.cancel = function () {
    if (timer) {
      clearTimeout(timer);
    }
  };
  return _debounce;
};
const debounceFn = debounce(inputChange, 2000, true);
inputEl.oninput = debounceFn;
cancelBtn.onclick = debounceFn.cancel;

When the content is input, the defined time from stopping input to clicking the button does not exceed (the above definition is 2 seconds), so only the function input for the first time will be executed, and it will not be executed when the user input is completed.

Step 5: function return value

The "anti shake" function defined above has no return value. If you want to get the execution result after execution, there are two ways to get it
Callback function
The fourth parameter is added to the input parameter of the anti shake function, which is a function used to obtain the result of the execution of the anti shake function

let count = 0;
const inputChange = function (event) {
  console.log(`The first ${++count}Call times, The input content is: ${event?.target?.value}`);
  return 'hello world'
};
const debounce = function (fn, delay, isImmediate = false, callbackFn) {
  let timer = null;
  let isExcute = isImmediate;
  const _debounce = function (...args) {
    if (isExcute) {
      const result = fn.apply(this, args);
      callbackFn(result)
      isExcute = false;
    }
    if (timer) {
      clearTimeout(timer);
    }
    timer = setTimeout(() => {
      const result = fn.apply(this, args);
      callbackFn(result)
      isExcute = isImmediate;
    }, delay);
  };
  return _debounce;
};
const debounceFn = debounce(inputChange, 2000, true, function(result){
  console.log('Get the result of execution',result)
});
inputEl.oninput = debounceFn;

Each time the anti shake function is executed, the contents of the callback function will be executed.

promise
In the return function of the anti shake function, the success or failure results are returned through promise. The following code only judges the successful execution conditions, and can also add the failed processing.
Asynchronous functions wrapped by promise can only get the response results after being called, so put the anti shake function in the new function and take the new function as the function of oninput event response.

const inputEl = document.querySelector("input");
  let count = 0;
  const inputChange = function (event) {
    console.log(
      `The first ${++count}Call times, The input content is: ${event?.target?.value}`
    );
    return "hello world";
  };
  const debounce = function (fn, delay, isImmediate = false) {
    let timer = null;
    let isExcute = isImmediate;
    const _debounce = function (...args) {
      return new Promise((resolve, reject) => {
        if (isExcute) {
          const result = fn.apply(this, args);
          resolve(result);
          isExcute = false;
        }
        if (timer) {
          clearTimeout(timer);
        }
        timer = setTimeout(() => {
          const result = fn.apply(this, args);
          resolve(result);
          isExcute = isImmediate;
        }, delay);
      });
    };
    // Encapsulation cancellation function
    _debounce.cancel = function () {
      if (timer) clearTimeout(timer);
      timer = null;
      isInvoke = false;
    };
    return _debounce;
  };
  const debounceFn = debounce(inputChange, 2000, true);
  const promiseCallback = function (...args) {
    debounceFn.apply(inputEl, args).then((res) => {
      console.log("promise Implementation results of", res);
    });
  };
  inputEl.oninput = promiseCallback;

Consistent with the form of the incoming callback function, it returns a result every time the anti shake function is executed.

In development, the anti shake function is used to optimize the performance of the project. It can be customized as above, or a third-party library can be used.

The above is the related content of anti shake function. There are still many places that developers need to master about js advanced. You can see other blog posts I wrote and keep updating~

Topics: Javascript Front-end