Why do we need to prevent and throttle

Such as REsize, Scroll, Mousemove, Click, keyDown, etc., trigger events with high frequency will excessively consume page performance, resulting in page lag and page jitter, especially when these event callback functions contain asynchronous operations such as Ajax. Multiple triggers can result in inconsistent results, resulting in results that are not the result of the last triggered event (there is no way to solve the problem of multiple Ajax returns being out of order). There are times when you don’t want to execute functions as often as you would like while the event continues to fire. At this time anti – shake and throttling is a better solution.

How much time interval is appropriate for consecutive calls

Most screens refresh at a rate of 60Hz per second, and browsers render pages at a standard frame rate of 60FPS. Browsers redraw 60 times per second, and the interval between frames is the minimum for DOM view updates.

For a smooth and fluid animation, the optimal loop interval (frame to frame switching time) is expected to be within 16.6ms(1s/60), meaning that multiple DOM changes in 17ms will be combined into one render.

When the callback takes longer than 16.6ms (the system screen limit refresh rate), the UI will lose frames (i.e., the UI will not be rendered at this moment), and the more frames are lost, the more stutter will occur.

Debounce function:

Idle control. The action will not be executed until N milliseconds have elapsed before the action is invoked. If the action is invoked within N milliseconds, the execution time will be recalculated.

Idle control: When the callback function is continuously invoked, the idle time must be greater than or equal to idle before the callback function is executed

The principle of

The action is executed N milliseconds after the action is called:

If this action is called again within N milliseconds, the execution time is recalculated:

implementation

Non-immediate version (The clear timer that is triggered multiple times in n seconds will be executed only once n seconds after the trigger is stopped)

The function is not executed immediately after the event is fired, but n seconds later. If the event is fired within n seconds, the function execution time is recalculated (consecutive clicks within n seconds will only be executed once after n seconds).

/ * * *@desc Function stabilization *@param Func callback function *@param Number of milliseconds to wait execution */ 
function debounce(func, wait) { 
    let timeout; 
    return function () { 
        let context = this; 
        let args = arguments; 
        // If timeout exists, clear the timer first.
        timeout?clearTimeout(timeout):null; 
        timeout = setTimeout(() = > { 
            So that debounce eventually returns this with the same reference and still accepts e.
            // Do not use apply to bind this func when this is the windowfunc.apply(context, args) }, wait); }}document.body.onclick= debounce(function () { console.log(this)},1000)
Copy the code

Immediate Release (The function executes immediately after the event is triggered by the callNow and timeout variables, and then fires the event again within n seconds without continuing the function)

The function executes immediately after the event is fired, and then fires the event again within n seconds without continuing the function. (Successive calls to the function within n seconds are executed only once at the beginning.)

/ * * *@desc Function stabilization *@param Func callback function *@param Number of milliseconds to wait execution */ 
function debounce(func,wait) { 
    let timeout; 
    return function () { 
        let context = this; 
        let args = arguments; 
        // Whether to execute the switch immediately
        // callNow is true if timeout does not exist
        letcallNow = ! timeout; timeout?clearTimeout(timeout):null; 
        timeout = setTimeout(() = > {  // Note that assigning timeout cannot be setTimeout
            timeout = null; 
        }, wait) 
        //callNow is true execute immediately (execute immediately on the first click)callNow? func.apply(context, args):null; }}document.body.onclick= debounce(function () { console.log(this)},1000)
Copy the code

Combination version

/ * * *@desc Function stabilization *@param Func function *@param Number of milliseconds to delay wait execution *@param Immediate true The table is executed immediately. False The table is not executed immediately */ 
function debounce(func,wait,immediate) { 
    let timeout; 
    return function () { 
        let context = this; 
        let args = arguments; 
        // Clear the timer on each execution, checking whether it exists just for rigor # clear the timer either way
        timeout?clearTimeout(timeout):null; 
        if (immediate) { 
            varcallNow = ! timeout; timeout =setTimeout(() = > { 
                timeout = null; 
            }, wait) 
            if (callNow) func.apply(context, args) 
        } else { 
            timeout = setTimeout(function(){ func.apply(context, args) }, wait); }}}document.body.onclick= debounce(function () { console.log(this)},1000.true)
Copy the code

Throttle:

Frequency control, so that a function can not be called in a very short interval of time, only when the last function has been executed after the specified time interval, the next call of the function.

Frequency control: The number of times the callback function is executed is limited by how often it is executed when an event is continuously fired.

The principle of

Delay execution interval = Delay time – (current execution time – last execution time)

implementation

Timestamp version: (using: now execution time – last execution time > delay time implementation)

(MouseMove, for example) the function is executed immediately the first time it is triggered, and every n seconds thereafter, and immediately the next time it is triggered

Suitable for Mousemove, Scroll, animation

function throttle(func, wait) { 
    // Last execution time
    let previous = 0; 
    return function() { 
        // The current time
        let now = Date.now(); 
        let context = this; 
        let args = arguments; 
        // The first time now-0 must be greater than wait executes immediately with previous = now
        // Perform each subsequent wait
        if(now - previous > wait) { func.apply(context, args); previous = now; }}}document.body.onmousemove= throttle(function () { console.log(1)},1000) 
Copy the code

Timer version: (using the repeated setting timeout implementation)

During a continuous event firing, the function is not executed immediately; 1s is executed first, and every 1s, and again after the event is stopped.

Suitable for keyDown and change

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) 
        } 
    } 
} 
document.body.onmousemove= throttle(function () { console.log(1)},1000) 
Copy the code

Double Sword combined round edition:

/ * * *@desc Function throttling@param Func function *@param Number of milliseconds to delay wait execution *@param Type 1 table timestamp version, 2 table timer version */ 
function throttle3(fn, wait, type = 1) {
    let pre = null
    let timeout = null
    if(type === 1){
        pre = 0
    }
    return function (){
        let context = this
        let args = arguments
        if(type === 1) {let now = new Date().getTime()
            if(now - pre > wait){
                fn.call(context, args)
                pre = now
            }
        }else {
            if(! timeout){ timeout =setTimeout(() = > {
                    timeout = null
                    fn.call(context, args)
                }, wait)
            }
        }
    }
}
document.body.onmousemove= throttle(function () { console.log(1)},1000.1) 
Copy the code

Debounce & Throttle – Use and timing

Purpose: in order to limit the execution frequency of the function, to optimize the function trigger frequency is too high resulting in the response speed can not keep up with the trigger frequency, the phenomenon of delay, false death or stuck. (1) Browser window size adjustment, Resize and Scroll events for window objects -> MouseDown and keydown events -> Debounce for mousedown and keydown events -> Throttle (2) for mousedown and keydown events -> Debounce Keypress -> Debounce (5) Function throttling and function buffering are used when the frequency of listening events is high

Debounce & Throttle – third party library

(1) Underscore. Js, provides a suite of functional programming utility features, 5.7KB (PROD version) (2) lodash.js ->.debounce() and.throttle() example: Add listen scroll event, $(window).on(‘scroll’, _. Debounce (doSomething, 16.7));

You can use a requestAnimationFrame instead of a timer

conclusion

1. Both anti-shock and throttling use function execution to return a function to form an undestroyed private scope

2. Put the counters and timers that need to be tired in the outer function

Function anti – shake and throttling optimization function trigger frequency too high