Quote from https://segmentfault.com/a/1190000018428170

Anti-shake and throttling should strictly be considered performance optimization knowledge, but in practice they are encountered quite frequently and can cause browsers to freeze if handled improperly or left unchecked. So it is necessary to master early. (Trust me, this will make sense.)

Starting with the scrollbar listener example, a common feature that many websites offer is a button that goes back to the top.

The button will only appear after scrolling a certain distance from the top, so we now abstract the function requirement — listen for the browser scroll event and return the current scroll distance from the top.

function showTop () { var scrollTop = document.body.scrollTop || document.documentElement.scrollTop; Console. log(' scrollbar position: '+ scrollTop); } window.onscroll = showTopCopy the code

But!

There is a problem at runtime: the default execution frequency of this function, too! High! ! . To what extent? In Chrome, for example, you can select a page by clicking the scroll bar, then click the Down arrow on the keyboard once, and see that the function executes 8 or 9 times!

However, we don’t really need such high frequency feedback, after all, browser performance is limited and should not be wasted here, so let’s discuss how to optimize this scenario.

Image stabilization (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 deadline value is given, such as 200ms, and then:

  • If the scroll event is not triggered again within 200ms, the function is executed
  • If the scroll event is triggered again within 200ms, the current timer is cancelled and the timer is restarted

Effect: If the same event is fired many times in a short period of time, the function is executed only once.

SetTimeout: setTimeout: setTimeout: setTimeout: setTimeout: setTimeout ()

/* * fn [function] delay [number] delay, Return function() {if(timer){clearTimeout(timer) */ function debounce(fn,delay){let timer = null // Enter the branch statement, indicating that a timing process is currently underway and the same event is triggered again. Timer = setTimeout(fn,delay)}else{timer = setTimeout(fn,delay)}Copy the code

Of course, the above code is to fit the idea, convenient to understand (so intimate not to give a praise? Time = setTimeout(fn,delay);

/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * simplified line * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * / function debounce (fn, delay) {let the timer = null Return function() {if(timer){clearTimeout(timer)} timer = setTimeout(fn,delay)} showTop () { var scrollTop = document.body.scrollTop || document.documentElement.scrollTop; Console. log(' scrollbar position: '+ scrollTop); } window.onscroll = debounce(showTop,1000)} window.onscroll = debounce(showTop,1000Copy the code

At this point, you will find that the scrollbar position will be printed only after stopping scrolling for 1 second.

At this point, anti-shake is implemented, now give the definition:

For events that occur in succession over a short period of time (the rolling event above), the idea is to have the event handler execute only once for a certain time period (1000 ms above).

The throttle (throttle)

Thinking further, the result of using the above anti-shake scheme to deal with the problem is:

  • If a scrolling event is triggered over and over again for a limited period of time (for example, if a user is idle and drags the scroll around), it will theoretically never output the current distance from the top as long as the trigger is not stopped.

But what if the product student’s expectation is that even if the user keeps dragging the scrollbar, there will be feedback after a certain interval? (No matter which scheme is more appropriate, we will consider how to achieve it now that the product father has spoken)

It’s pretty simple: we can design a function that opens periodically, like a control valve, that runs once, shuts down for a certain period of time, and then reactivates after that period (similar to a cooldown).

Effect: If a large number of the same events are fired in a short period of time, the function stops working for a specified period of time after it executes once, and does not take effect again until that time has passed.

Use setTimeout to do a simple implementation, plus a status bit valid to indicate whether the current function is working:

function throttle(fn,delay){ let valid = true return function() { if(! Valid){// Rest time no call return false} // Work time, execute the function and set the status bit to invalid during the interval valid = false setTimeout(() => {fn() valid = true; }, delay) } }Copy the code
  • Note that the throttling function is not implemented in the same way as above. For example, setTimeout can be dispensed with entirely, the status bit can be replaced with a timestamp, and then the timestamp difference can be determined by whether the timestamp difference is greater than the specified interval. Also, the return mark of setTimeout can be directly used as a judgment condition – to determine whether the current timer exists. If it exists, it indicates that it is still cooling down, and eliminating the timer after the execution of FN indicates activation. The principle is the same *

// As usual

function showTop () { var scrollTop = document.body.scrollTop || document.documentElement.scrollTop; Console. log(' scrollbar position: '+ scrollTop); } window.onscroll = throttle(showTop,1000)Copy the code

The result of running the above code is:

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

With these two tips covered, here are some common development scenarios: Search box input events, for example, to support input real-time search, you can use throttling scheme (interval of a period of time must query the relevant content), or achieve input interval greater than a certain value (such as 500ms), as the user input is completed, and then start the search, the specific use of which scheme depends on business requirements. The page resize event is usually used when page adaptation is needed. Dom rendering is required based on the final rendering of the page (this is usually done using anti-shake, since only the last change is needed)Copy the code

Involves knowledge expansion closures