The summary of js anti shake and throttle

Keywords: Front-end less Javascript

In recent projects, the test proposed that clicking the button quickly for many times would trigger multiple calls of the interface. Later, when querying the data, you can use the anti shake optimization, which just integrates the use of anti shake and throttling for your own learning

Code:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
    <title>test</title>
	<style>
	</style>    
    <script type="text/javascript" charset="UTF-8">
    </script>
</head>
<body>
	<button class="mui-content" id="test">
      //Button click event
  </button>
  <p id="ptest"></p>
  <script>
    let num = 10;
    let content = document.getElementById('test');
    let pcontent = document.getElementById('ptest');
    function count() {
      console.log("----Calculate---")
      pcontent.innerHTML = ++num;
    };
    content.onclick = count;
   
  </script>
</body>
</html>

Effect picture after 3 clicks of the button

Description:

In the window resize, scroll, input content input and verification, button button continuous click and other operations, if the frequency of event processing function call is unlimited, it will increase the burden of browser, resulting in poor user experience, at this time we can use anti shake and flow saving

Debounce

Definition:

The function can only be executed once in n seconds after an event is triggered. If an event is triggered again in n seconds, the function execution time will be recalculated

Anti shake function:

It can be divided into immediate version and non immediate version

Execute version now:

After the event is triggered, the function will execute immediately, and then the event will be triggered repeatedly within n seconds. The func callback function will only call once, and no event will be triggered within n seconds, so as to execute the function

function debounce(func,wait) {
    let timeout;
    return function () {
        let context = this;
        let args = arguments;

        if (timeout) clearTimeout(timeout);

        let callNow = !timeout;
        timeout = setTimeout(() => {
            timeout = null;
        }, wait)

        if (callNow) func.apply(context, args)
    }
}

Use the execute now function to modify the above code as follows:

<script>
    let num = 10;
    let content = document.getElementById('test');
    let pcontent = document.getElementById('ptest');
    function count() {
      console.log("----Calculate---")
      pcontent.innerHTML = ++num;
    };
    content.onclick = debounce(count, 1000);
    function debounce(func,wait) {
    let timeout;
    return function () {
        let context = this;
        let args = arguments;
        if (timeout) clearTimeout(timeout);
        console.log("-------output timeout Value----")
        console.log(timeout)
        let callNow = !timeout;
        console.log("----------callNow---------")
        console.log(callNow)
        timeout = setTimeout(() => {
            timeout = null;
            alert("Execute function effect")
        }, wait)
        if (callNow) func.apply(context, args)
    }
}
  </script>

If function events are triggered continuously within n seconds, the value of callNow will be true only when the first trigger occurs, and false for others. That is to say, func callback function can only be called once. If no trigger function event is detected within n seconds, it will print "--------- function execution effect -----------"

Design sketch:

Non immediate version:

The function will not execute immediately after the event is triggered, but after n seconds. If the event is triggered again within n seconds, the function execution time will be recalculated

function debounce(func, wait) {
    let timeout;
    return function () {
        let context = this;
        let args = arguments;

        if (timeout) clearTimeout(timeout);
        
        timeout = setTimeout(() => {
            func.apply(context, args)
        }, wait);
    }
}

Design sketch:

The code of the above anti shake function also needs to pay attention to the transfer of this and parameters

let context = this;
let args = arguments;

The code of the anti shake function uses these two lines of code to get this and parameters, in order to make the last returned function of the debounce function point to the same and still accept the e parameter.

In the development process, we need to decide which version of the anti shake function we need to use according to different scenarios. Generally speaking, the above anti shake functions can meet most of the scenario requirements. However, we can also combine the anti shake functions of the non immediate version and the immediate version to realize the final anti shake function of the two sword version.
 

Double sword version:

/**
 * @desc Function anti shake
 * @param func function
 * @param wait Delay execution milliseconds
 * @param immediate true Table execute immediately, false table execute not immediately
 */
function debounce(func,wait,immediate) {
    let timeout;

    return function () {
        let context = this;
        let args = arguments;

        if (timeout) clearTimeout(timeout);
        if (immediate) {
            var callNow = !timeout;
            timeout = setTimeout(() => {
                timeout = null;
            }, wait)
            if (callNow) func.apply(context, args)
        }
        else {
            timeout = setTimeout(function(){
                func.apply(context, args)
            }, wait);
        }
    }
}

The difference between immediate and non immediate versions is summarized in the figure above

. Immediate execution is the function call in front and the effect execution in the back

. Non immediate execution means that both function call and effect execution are after

Throttle:

It means that the function is triggered continuously but executed only once in n seconds, and throttling will dilute the execution frequency of the function.

For throttling, there are generally two ways to achieve, namely time stamp version and timer version.

Timestamp version:

function throttle(func, wait) {
    let previous = 0;
    return function() {
        let now = Date.now();
        let context = this;
        let args = arguments;
        if (now - previous > wait) {
            func.apply(context, args);
            previous = now;
        }
    }
}

Timer version:

function throttle(func, wait) {
    let timeout;
    return function() {
        let context = this;
        let args = arguments;
        if (!timeout) {
            timeout = setTimeout(() => {
                timeout = null;
                func.apply(context, args)
            }, wait)
        }

    }
}

Two swords version 1:

/**
 * @desc Function throttling
 * @param func function
 * @param wait Delay execution milliseconds
 * @param type 1 Table time stamp version, 2 table timer version
 */
function throttle(func, wait ,type) {
    if(type===1){
        let previous = 0;
    }else if(type===2){
        let timeout;
    }
    return function() {
        let context = this;
        let args = arguments;
        if(type===1){
            let now = Date.now();

            if (now - previous > wait) {
                func.apply(context, args);
                previous = now;
            }
        }else if(type===2){
            if (!timeout) {
                timeout = setTimeout(() => {
                    timeout = null;
                    func.apply(context, args)
                }, wait)

            }
        }
    }
}

Combination of two swords 2

We consider combining the two methods, fn will be executed when the event is triggered for the first time, the interval between the last time and the previous time is relatively short, and func will be executed again after wait.

var throttle = function (func, wait) {
  var flag, _start = Date.now();
  return function () {
    var context = this,
      args = arguments,
      _now = Date.now(),
      remainTime = wait - (_now - _start);
    if(remainTime <= 0) {
      fn.apply(this, args);
    } else {
      setTimeout(function () {
        fn.apply(this, args);
      }, remainTime)
    }    
  }
}

The difference of throttling function between time stamp version and timer version:

. The function trigger of the time stamp version starts at the beginning of the time period. Using the time stamp method, the timing will start when the page is loaded. If the page load time is greater than the wait we set, the first time the event callback is triggered, it will immediately func without delay. If the time difference between the last trigger callback and the previous trigger callback is less than wait, the last trigger event will not execute func;

. The function trigger of timer version is at the end of the time period. Using timer mode, we will start timing when we first trigger the callback. If the time interval between the last trigger callback event and the previous one is less than wait, func will still be executed after the wait.

The difference between function anti shake and function throttle

Through the above analysis, we can clearly see the difference between function anti shake and function throttling:

In case of frequent triggering events, the function anti shake will only execute the callback content in the last triggering event. In other cases, the delay event will be recalculated, and the function throttling will execute the callback function at regular intervals.

Be careful:

  1. Anti shake and throttling only reduce the number of times the event callback function executes, but not the frequency of event triggering.

  2. Anti shake and throttling don't solve the performance problem in essence. We should also pay attention to optimizing the logic function of our event callback function, avoiding more complex DOM operations in the callback, and reducing browser reflow and retain.

 

Reference resources: https://www.jianshu.com/p/c8b86b09daf0

https://www.cnblogs.com/zhuanzhuanfe/p/10633019.html

Posted by shamuraq on Fri, 13 Mar 2020 03:24:07 -0700