js performance optimization: thoroughly understand function anti-shake and function throttling

Function anti-shake and throttling

Function anti-shake and function throttling: A means to optimize high-frequency execution of js code. When some events in js, such as browser resize, scroll, mousemove, mouseover, and input box keypress, are triggered, they will Continuously calling the callback function bound to the event greatly wastes resources and reduces front-end performance. In order to optimize the experience, it is necessary to limit the number of calls to this type of event.

Function anti-shake

The callback is executed n seconds after the event is triggered, and if it is triggered again within these n seconds, the timer is restarted.

According to the function anti-shake idea, the first version of the simplest anti-shake code is designed:

<code>var timer; // maintain the same timer<br>
function debounce(fn, delay) {<!-- --><br>
clearTimeout(timer);<br>
timer = setTimeout(function(){<!-- --><br>
fn();<br>
}, delay);<br>
}<br>
</code>

Use onmousemove to test the anti-shake function:

<code>// test<br>
function testDebounce() {<!-- --><br>
console. log('test');<br>
}<br>
document.onmousemove = () => {<!-- --><br>
debounce(testDebounce, 1000);<br>
}<br>
</code>

The debounce in the above example is the anti-shake function. When the mouse moves in the document, the callback function testDebounce will be executed 1s after the last trigger of onmousemove; if we keep moving the mouse in the browser (such as 10s), we will find that it will The testDebounce function will be executed after 1s (because of clearTimeout(timer)), this is the function anti-shake.

In the above code, there will be a problem, var timer can only be in the parent scope of setTimeout, so it is the same timer, and in order to facilitate the call of the anti-shake function and the parameter passing of the callback function fn, we should Use closures to solve these problems.

Optimized code:

<code>function debounce(fn, delay) {<!-- --><br>
var timer; // maintain a timer<br>
return function () {<!-- --><br>
var _this = this; // Get the this of the debounce execution scope<br>
var args = arguments;<br>
if (timer) {<!-- --><br>
clearTimeout(timer);<br>
}<br>
timer = setTimeout(function () {<!-- --><br>
fn.apply(_this, args); // Use apply to point to the object calling debounce, equivalent to _this.fn(args);<br>
}, delay);<br>
};<br>
}<br>
</code>

Test case:

<code>// test<br>
function testDebounce(e, content) {<!-- --><br>
console. log(e, content);<br>
}<br>
var testDebounceFn = debounce(testDebounce, 1000); // debounce function<br>
document.onmousemove = function (e) {<!-- --><br>
testDebounceFn(e, 'debounce'); // pass parameters to debounce function<br>
}<br>
</code>

After using the closure, solve the problem of passing parameters and encapsulating the anti-shake function, so that you can pass the function that needs anti-shake to debounce in other places.

Function throttling

Every once in a while, the function is executed only once.

  • The timer implements the throttling function:

Please carefully look at the code difference with the anti-shake function

<code>function throttle(fn, delay) {<!-- --><br>
var timer;<br>
return function () {<!-- --><br>
var _this = this;<br>
var args = arguments;<br>
if (timer) {<!-- --><br>
return;<br>
}<br>
timer = setTimeout(function () {<!-- --><br>
fn.apply(_this, args);<br>
timer = null; // Clear the timer after executing fn after the delay, at this time the timer is false, and the throttle trigger can enter the timer<br>
}, delay)<br>
}<br>
}<br>
</code>

Test case:

<code>function testThrottle(e, content) {<!-- --><br>
console. log(e, content);<br>
}<br>
var testThrottleFn = throttle(testThrottle, 1000); // throttle function<br>
document.onmousemove = function (e) {<!-- --><br>
testThrottleFn(e, 'throttle'); // pass parameters to the throttle function<br>
}<br>
</code>

In the above example, if we keep moving the mouse in the browser (for example, 10s), then testThrottle will be executed every 1s during the 10s, which is the function throttling.

The purpose of function throttling is to limit the function to be executed only once within a period of time. Therefore, the timer implements the throttling function by using the timed task, and the delay method is executed. During the delay time, if the method is triggered, the method will be exited directly. Thus, the implementation function is executed only once in a period of time.

According to the principle of function throttling, we can also realize function throttling without relying on setTimeout.

  • Timestamp implements throttling function:
<code>function throttle(fn, delay) {<!-- --><br>
var previous = 0;<br>
// Use a closure to return a function and use the variable previous outside the closure function<br>
return function() {<!-- --><br>
var _this = this;<br>
var args = arguments;<br>
var now = new Date();<br>
if(now - previous > delay) {<!-- --><br>
fn.apply(_this, args);<br>
previous = now;<br>
}<br>
}<br>
}<br>
// test<br>
function testThrottle(e, content) {<!-- --><br>
console. log(e, content);<br>
}<br>
var testThrottleFn = throttle(testThrottle, 1000); // throttle function<br>
document.onmousemove = function (e) {<!-- --><br>
testThrottleFn(e, 'throttle'); // pass parameters to the throttle function<br>
}<br>
</code>

Its implementation principle is to judge whether to execute the function by comparing the time difference between the last execution time and the current execution time and the interval time. If the time difference is greater than the interval time, the function will be executed immediately. And update the last execution time.

Comparison of similarities and differences

Same point:

  • Both can be achieved by using setTimeout.
  • The purpose is to reduce the frequency of callback execution. Save computing resources.

difference:

  • Function anti-shake, after a period of continuous operation, handle the callback, use clearTimeout and setTimeout to achieve. Function throttling, in a continuous operation, executes only once per period of time, used in events with high frequency to improve performance.
  • Function anti-shake focuses on events that are triggered continuously for a certain period of time and only executes once at the end, while function throttling focuses on executing only once within a period of time.

Common application scenarios

Application scenario of function anti-shake

For continuous events, only one callback needs to be triggered:

  • Search box Search input. Only the user needs to enter the last time before sending the request
  • Mobile phone number, email verification input detection
  • Window size Resize. Just calculate the window size after the window resizing is done. Prevent re-rendering.

Application scenario of function throttling

Scenarios for executing callbacks at intervals include:

  • Scroll to load, load more or scroll to the bottom to listen
  • Google search box, search association function
  • Frequent clicks to submit, repeated form submissions