Home > Article > Web Front-end > Clever usage of setTimeout in JS front-end function throttling
What is function throttling?
Function throttling simply means that we do not want the function to be called continuously in a short period of time. For example, the most common thing we do is when the window is zoomed, we often execute some other operation functions, such as sending An ajax request and other things, then when the window is zoomed, it is possible to send multiple requests continuously, which is not what we want, or our common mouse movement in and out tab switching effect, sometimes continuous and moving Soon, there will be a flickering effect. At this time, we can use function throttling to operate. As we all know, DOM operations will be very consuming or affect performance. If a large number of DOM operations are bound to elements when the window is zoomed, it will cause a large number of continuous calculations. For example, under IE, too many DOM operations will occur. The operation will affect the browser performance, and even cause the browser to crash in severe cases. At this time we can use function throttling to optimize the code~
The basic principle of function throttling:
Use a timer to first delay the function Execution, for example, use the setTomeout() function to delay the execution of the function for a period of time. If other events are triggered during this time period, we can use the clearTimeout() method to clear the timer, and then setTimeout() a new timer. The server delays execution for a while.
Recently, a team is busy with a project. There is a page like this, which is developed in the traditional mode (complaining about why it does not use React). It has a lot of DOM operations, and its performance is relatively poor, especially when you zoom in and out of the window. Sometimes, something terrible happens, it freezes, or even the browser crashes. why?
Since this page has a lot of DOM operations, the execution of the function will be triggered every frame when the window is zoomed, and the DOM operations will be repeated continuously, which is very expensive for the browser. Since the browser will recalculate the DOM when the window is zoomed, why can't we delay the calculation of the DOM and let the window stop zooming before recalculating it? This will save the browser's overhead and achieve the optimization effect. Yet?
Knowledge preparation
1. setTimeout(code,millisec) is of course the protagonist of this article.
The setTimeout() method is used to call a function or calculated expression after a specified number of milliseconds.
code is required. The string of JavaScript code to be executed after the function to be called.
millisec is required. The number of milliseconds to wait before executing code.
Tip: setTimeout() only executes code once. If you want to call it multiple times, use setInterval() or have the code itself call setTimeout() again.
Widely used in timers, carousels, animation effects, automatic scrolling, etc.
2. clearTimeout(id_of_setTimeout)
Parameter id_of_settimeout is the ID value returned by setTimeout(). This value identifies the deferred execution code block to be canceled.
3. fun.apply(thisArg[, argsArray])
apply() method specifies this value and parameters (the parameters are in the form of arrays or array-like objects Call a function when exists)
The syntax of this function is almost the same as the call() method. The only difference is that the call() method accepts a parameter list, while apply() Accepts an array (or array-like object) containing multiple parameters.
Parameters
thisArg
The this value specified when the fun function is running. It should be noted that the specified this value is not necessarily the real this value when the function is executed. If the function is in non-strict mode, it will automatically point to the global object (window object in the browser) when it is specified as null or undefined. ), and this, whose value is a primitive value (number, string, Boolean value), will point to the automatic wrapping object of the primitive value.
argsArray
An array or array-like object whose array elements will be passed to the fun function as separate parameters. If the value of this parameter is null or undefined, it means that no parameters need to be passed in. Starting from ECMAScript 5, array-like objects are available.
When calling an existing function, you can specify a this object for it. this refers to the current object, which is the object that is calling this function. Using apply, you can write the method once and then inherit it in another object, without having to write the method repeatedly in the new object.
4. fun.call(thisArg[, arg1[, arg2[, ...]]])
This method uses a specified this value and Call a function or method under the premise of several specified parameter values.
Parameters
thisArg
When the fun function is running The specified this value. It should be noted that the specified this value is not necessarily the real this value when the function is executed. If the function is in non-strict mode, the this value specified as null and undefined will automatically point to the global object (in the browser, it is window object), and this whose value is a primitive value (number, string, Boolean value) will point to the automatic wrapping object of the primitive value.
arg1, arg2, ...
Specified parameter list.
When calling a function, you can assign a different this object. this refers to the current object, the first parameter of the call method. Through the call method, you can borrow methods on one object from another object, such as Object.prototype.toString.call([]), which is an Array object borrowing methods on the Object object.
Function:
Use the call method to call the parent constructor
Use the call method to call the anonymous function
Use the call method to call an anonymous function and specify the 'this' of the context
Insert a digression here:
apply is very similar to call(), the difference is that How to provide parameters. apply uses an array of arguments rather than a list of arguments. apply can use array literals, such as fun.apply(this, ['eat', 'bananas']), or array objects, such as fun.apply(this, new Array('eat', 'bananas' )). You can also use arguments objects as argsArray parameters. arguments are local variables of a function. It can be used as any unspecified parameter of the called object. In this way, you don't need to know all the parameters of the called object when using the apply function. You can use arguments to pass all arguments to the called object. The called object is then responsible for processing these parameters.
Starting with ECMAScript version 5, you can use any kind of array-like object, that is, as long as it has a length property and an integer property in the range [0...length). For example, you can now use NodeList or a self-defined object similar to {'length': 2, '0': 'eat', '1': 'bananas'}.
The difference between the call and apply methods is that starting from the second parameter, the call method parameters will be passed to the borrowed method as parameters in turn, while apply directly puts these parameters into an array and then passes them. Finally, the parameter list of the borrowed method is the same.
Application scenario: when the parameters are clear, call can be used, and when the parameters are unclear, apply can be used to give the arguments
Now first Give an example
As we all know, onscolll, onresize, etc. are very performance-intensive, and numbers are printed when the window is zoomed.
var count = ; window.onresize = function () { count++; console.log(count); }
Stretch the browser window size in the chrome browser and print it as follows
This is obviously not what we want Yes, if we switch to an ajax request, the window will be scaled once and multiple ajax requests will be triggered in succession. Let's try using the function throttling operation; of course, just add a settimeout() timer. Yes,
The first encapsulation method
var count = ; function oCount() { count++; console.log(count); } window.onresize = function () { delayFun(oCount) }; function delayFun(method, thisArg) { clearTimeout(method.props); method.props = setTimeout(function () { method.call(thisArg) }, ) }
The second encapsulation method
Construction A closure uses closure to form a private scope to store the timer. The timer is introduced by passing parameters.
var count = ; function oCount() { count++; console.log(count); } var funs= delayFun(oCount,); window.onresize = function () { funs() }; function delayFun(func, wait) { var timer = null; return function () { var context = this, args = arguments; clearTimeout(timer); timer = setTimeout(function () { func.apply(context, args); }, wait) }; }
Optimize the second method, the performance will be better
Here returns a function, if it is called without interruption, it will not be executed. The function will not be executed until it is called again N milliseconds after it stops being called. If the 'immediate' parameter is passed, the function will be scheduled to the execution queue immediately without delay.
function delayFun (func, wait, immediate) { var timeout; return function() { var context = this, args = arguments; var later = function() { timeout = null; if (!immediate) func.apply(context, args); }; var callNow = immediate && !timeout; clearTimeout(timeout); timeout = setTimeout(later, wait); if (callNow) func.apply(context, args); }; }; // 用法 var myEfficientFn = delayFun (function() { // 所有繁重的操作 }, ); window.addEventListener('resize', myEfficientFn);
The function does not allow the callback function to be executed more than once within the specified time. This function is particularly important when assigning a callback function to an event that will be triggered frequently.
setTimeout is so powerful, can we use it extensively in projects?
I personally do not recommend it. In our business, it is basically forbidden to use setTimeout in business logic, because many of the usage methods I have seen are some problems that are easy to solve. SetTimeout As a hack.
For example, when an instance has not been initialized, we use this instance. The wrong solution is to add a setTimeout when using the instance to ensure that the instance is initialized first.
Why is it wrong? This is actually a method of using hacks
The first is to lay a trap and disrupt the life cycle of the module
The second is that when a problem occurs, setTimeout is actually very Difficult to debug.
Regarding the clever use of setTimeout in JS and front-end function throttling, the editor will introduce it to you here. I hope it will be helpful to you!
For more clever usage of setTimeout in JS and related articles on front-end function throttling, please pay attention to the PHP Chinese website!