Anti shake and throttling

Posted by Fredix on Fri, 08 Oct 2021 03:27:06 +0200

Original link: https://segmentfault.com/a/1190000018428170

1. Why do anti shake and throttling occur

Anti shake and throttling should belong to the knowledge of performance optimization strictly, but in fact, the frequency encountered is quite high. Improper handling or laissez faire will easily cause the browser to get stuck. So it is necessary to master it early.

Let's start with the example of scroll bar monitoring

Let's start with a common function. Many websites will provide such a button: to return to the top.

This button will only appear after scrolling to a certain position from the top, so let's abstract this function requirement now--   Listen to the browser scroll event and return the distance between the current scroll bar and the top
This requirement is very simple. Write it directly:

function showTop  () {
    var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
  console.log('Scroll bar position:' + scrollTop);
}
window.onscroll  = showTop

  But!

When running, you will find that there is a problem: the default execution frequency of this function is too high! High! It's too late!.   To what extent? Taking chrome as an example, we can click the scroll bar of a page, and then click the down key on the keyboard once. We will find that the function has been executed 8-9 times!

  However, in fact, we do not need such high-frequency feedback. After all, the performance of the browser is limited and should not be wasted here, so we will discuss how to optimize this scenario.

2. Debounce

Based on the above scenario, the first idea is proposed: when the event is triggered for the first time, the function is not executed immediately, but a period value, such as 200ms, is given, and then:

  • If the scroll event is not triggered again within 200ms, the function is executed
  • If the rolling event is triggered again within 200ms, the current timing will be cancelled and the timing will be restarted

Effect: if the same event is triggered in a large number in a short time, the function will be executed only once.

Implementation: since timing has been mentioned earlier, the key to implementation lies in the setTimeout function. Since a variable is needed to save timing and maintain global purity, it can be implemented with the help of closed packets:

/*
* fn [function] Functions requiring anti shake
* delay [number] MS, anti shake duration value
*/
function debounce(fn,delay){
    let timer = null //With closures
    return function() {
        if(timer){
            clearTimeout(timer) //Entering the branch statement indicates that the current timing process is in progress and the same event is triggered. So cancel the current timing and restart the timing
            timer = setTimeout(fn,delay) 
        }else{
            timer = setTimeout(fn,delay) // Entering this branch indicates that there is no timing at present, so start a timing
        }
    }
}

Of course, the above code is to fit the idea and facilitate understanding. After writing, you will find that time = setTimeout(fn,delay) will be executed, so you can simplify it a little:

/*****************************Simplified split line******************************/
function debounce(fn,delay){
    let timer = null //With closures
    return function() {
        if(timer){
            clearTimeout(timer) 
        }
        timer = setTimeout(fn,delay) // Simplified writing
    }
}
// Then the old code
function showTop  () {
    var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
  console.log('Scroll bar position:' + scrollTop);
}
window.onscroll = debounce(showTop,1000) // In order to facilitate the observation of the effect, we take a large intermittent value and configure it according to the actual use

At this time, you will find that the scroll bar position will not be printed until you stop scrolling for 1 second.

So far, anti shake has been implemented. Now give the definition:

  • For events triggered continuously in a short time (the above rolling event), anti shake means that the event handling function is executed only once within a certain time period (such as the above 1000 milliseconds).

3. Throttle

Continue to think. The result of using the above anti shake scheme to deal with the problem is:

  • If scrolling events are triggered continuously within a limited period of time (for example, a user is idle and bored, press and hold scrolling and drag constantly), as long as the trigger is not stopped, theoretically, the current distance from the top will never be output.

But what if the expected solution of the product students is: even if the user keeps dragging the scroll bar, he can give feedback after a certain time interval?

In fact, it is very simple: we can design a function that opens regularly like a control valve, that is, after the function is executed once, it will temporarily fail in a certain period of time, and then reactivate after this period of time (similar to the skill cooling time).

Effect: if a large number of the same events are triggered in a short time, after the function is executed once, the function will not work within the specified time period until it takes effect again.

realization   Here, a simple implementation is made with the help of setTimeout, and a status bit valid is added to indicate whether the current function is in the working state:

function throttle(fn,delay){
    let valid = true
    return function() {
       if(!valid){
           //No pick-up during break time
           return false 
       }
       // Working time, execute the function and set the status bit to invalid during the interval
        valid = false
        setTimeout(() => {
            fn()
            valid = true;
        }, delay)
    }
}
/* Please note that the throttling function is not just the above implementation scheme,
   For example, without the aid of setTimeout, you can replace the status bit with a timestamp, and then use whether the timestamp difference is greater than the specified interval to make a decision.
   You can also directly take the returned flag of setTimeout as the judgment condition - judge whether the current timer exists. If it exists, it means that it is still cooling, and after fn is executed, it means that the timer is activated. The principle is the same
    */

// Business as usual
function showTop  () {
    var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
  console.log('Scroll bar position:' + scrollTop);
}
window.onscroll = throttle(showTop,1000) 

The result of running the above code is:

  • If you keep dragging the scroll bar to scroll, the distance between the current position and the top will be continuously output at an interval of 1s

4. Examples of other application scenarios

After talking about these two skills, let's introduce the common scenarios in daily development:

  1. For the input event of the search box, for example, to support input real-time search, you can use the throttling scheme (you must query the relevant content after a period of time), or realize that the input interval is greater than a certain value (such as 500ms), which is regarded as user input, and then start the search. The specific scheme depends on the business requirements.
  2. The page resize event is common when page adaptation is required. dom rendering needs to be performed according to the final rendered page (in this case, anti shake is generally used, because only the last change needs to be judged)

Topics: Javascript html5