preface

Front-end development will encounter some frequent events triggered, such as: Window scroll, resize; Mousedown, Mousemove, KeyUp, keyDown, etc., if you do not do anything to your code, you will find that the page is stuck, trigger interface requests frequently and other problems, this article will analyze the function throttling and anti-shaking implementation, step by step gradually reveal the function throttling and anti-shaking true 💜

concept

Understand the principle of anti-shake and throttling trigger, and use them properly according to different application scenarios

Function debounce

If the action is invoked within n milliseconds, the execution time is recalculated and the action is not executedCopy the code

Understanding principle: although trigger event, but must be in the event triggered n seconds after the execution, if an event triggered within n seconds and triggered the event, with the time of the new event shall prevail, n seconds after the execution, in short, is to trigger the event within n seconds no longer triggered event, will be executed!

Function throttle

A predetermined execution period is set to execute the action at a time greater than or equal to the execution period, and then the next new periodCopy the code

Understanding principle: within a specified time, ensure the execution of this function

implementation

Image stabilization

According to the principle of anti-shake, the implementation code is as follows, and the following examples will be used in general:

# arrow log function
let count = 0
const log = () => {
    console.log(this)
    ++count
    console.log(count)
}
# function expression
const log = function (evt) {
    console.log(this)
    console.log(evt)
    ++count
    console.log(count)
}
Copy the code
const debounce = function (fn, delay){
    let timeout = null
    return function () {
        if (timeout) {
            clearTimeout(timeout)
        }
        timeout = setTimeout(fn, delay)
    }
}
Copy the code

Onclick = debounce(log, 1000) React Demo:… onClick={debounce(log.bind(this), 1000)}

Have you found that there are still defects in the anti-shake function at this time

  • This points to and event objects
  • If the user keeps clicking the submit button now, the request will never be sent and will not be prompted, which is pretty bad for the user experience

This points to and event objects

This points to the

  • In the log function console.log(this), the value of this is undefined when debounce is not used. This is because the arrow function is used and bind(this) is called when onClick is called. This points to the react component example
  • In conventional use console.log(this), when debounce is not used, the value of this is:<div id="mecontain"></div>

The event object

  • Without the debouce function, the ClickEvent object is printed
  • The debounce function, however, prints only undefined

Solve the above problems to change our code

const debounce = function (fn, delay){
    let timeout = null
    return function () {
        const context = this;
        const args = arguments;
        clearTimeout(timeout)
        timeout = setTimeout(() => {
            fn.apply(context, args)
        }, delay)
    }
}
Copy the code

Interactive optimization experience

If you want to execute the function immediately, do not wait until the event stops triggering. After the event stops triggering for n seconds, you can trigger the function again by adding isImmeDiate to check whether the function is executed immediately

const debounce = function (fn, delay,isImmeDiate= false) {let timeout = null
    return function () {
        const context = this;
        const args = arguments;
        if(timeout) clearTimeout(timeout)
        if(isImmeDiate) {
            # Check if it has already been executed, do not repeat execution
            letcallNow = ! timeout timeout =setTimeout(function(){
                timeout = null;
             }, delay)
            if(callNow)  result = fn.apply(context, args)
        } else {
            timeout = setTimeout(() => {
                fn.apply(context, args)
            }, delay)
        }
        return result
    }
}
Copy the code

To add a cancel debounce switch, simply add a cancle function to clear timer timeout = null

const debounce = function (fn, delay,isImmeDiate= false) {let timeout = null
    const debounced =  function () {
        const context = this;
        const args = arguments;
        if(timeout) clearTimeout(timeout)
        if(isImmeDiate) {
            # Check if it has already been executed, do not repeat execution
            # setTimeout is also constantly updated
            letcallNow = ! timeout timeout =setTimeout(function(){
                timeout = null;
             }, delay)
            if(callNow)  result = fn.apply(context, args)
        } else {
            timeout = setTimeout(() => {
                fn.apply(context, args)
            }, delay)
        }
        return result
    }
    debounced.prototype.cancle = function() {
        clearTimeout(timeout)
        timeout = null
    }
    return debounced
}
Copy the code

So far we have implemented an anti-shake function, but do you have any other ideas?

The throttle

According to the principle of throttling, the implementation code is as follows, and the following examples will be used in general:

Timestamp implementation

const throttle = function (fn, delay) {
    let preTime = 0;
    return function () {
        const context = this;
        const args = arguments;
        const now = +new Date();
        if(now - preTime > delay) { fn.apply(context, args); preTime = now; }}}Copy the code

Timer implementation

const throttle = function (fn, delay) {
    let timeout = null
    return function () {
        const context = this;
        const args = arguments;
        if(! timeout) { timeout =setTimeout(function(){
                timeout = null
                fn.apply(context, args)
            }, delay)
        }
    }
}
If you need to execute it immediately, change the order of execution
timeout = setTimeout(function(){
    timeout = null
    //fn.apply(context, args)
}, delay)
fn.apply(context, args)
Copy the code

MeContain. Onclick = throttle(log, 1000)

Have you found the characteristics of the throttle function at this time

  • The timestamp is executed immediately and the timer is executed for the first time in n seconds
  • There is no way to execute the event after the timestamp stops firing. The timer implementation will execute the event again even after it stops firing

Combine the two

const throttle = function (fn, delay) {
    let timeout = null
    let preTime = 0;
    const later = function() {
        preTime = +new Date()
        timeout = null
        fn.apply(context, args);
    }
    const throttled = function () {
        const context = this;
        const args = arguments;
        const now = +new Date();
        # Time remaining for the next fn trigger
        const remaining = delay - ( now - preTime)
        If there is no time left or the system time changes
        if (remaining <= 0 || remaining > delay) {
            if(timeout) {
                clearTimeout(timeout)
                timeout = null
            }
            preTime = now
           fn.apply(context, args);
        } else if(! timeout) { timeout =setTimeout(later, remaining)
        }
    }
    throttled.cancel = function() {
        clearTimeout(timeout);
        previous = 0;
        timeout = null;
    }
    return throttled
}
Copy the code

conclusion

Throttling, within a specified period of time, to ensure the execution of the function; When the event is triggered continuously and no event is triggered again within a certain period of time, the event handler function will be executed once. If the event is triggered again before the set time, the delay will start again

The document

Talk about function anti-shake function throttling function anti-shake function throttling

Sell yourself

Learn about Vue error handling Webpack DllPlugin to make build speed smooth and silky