What is function throttling?
Function throttling simply means that we don’t 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 perform some other operation functions, such as sending an ajax request. Wait, then when the window is zoomed, it is possible to send multiple requests continuously, which is not what we want, or our common tab switching effect of moving the mouse in and out, sometimes continuously and very quickly. Sometimes, 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~
Basic principles of function throttling:
Use a timer to delay the execution of the function first. For example, use the setTomeout() function to delay the execution of the function for a period of time. If other events are triggered within this time period, we can use the clearing method clearTimeout() To clear the timer, setTimeout() a new timer to delay 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, it is terrible. Something happened, lags occurred, or even the browser crashed. 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. Already?
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)
The 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])
The apply() method calls a function by specifying this value and parameters (the parameters exist in the form of an array or array-like object)
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, the array elements of which will be passed as separate parameters to the fun function. 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 calls a function or method using a specified this value and several specified parameter values.
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, the this value specified as null and undefined will automatically point to the global object (in the browser, this 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, ...
The 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 anonymous functions
Use the call method to call an anonymous function and specify the context's 'this'
A digression here:
apply is very similar to call(), the difference lies in the way the parameters are provided. apply uses an array of parameters rather than a set of parameter lists. 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 arguments. 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 from 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, while apply directly puts these parameters into an array and then passes them, and finally the parameter list of the borrowed method It’s the same.
Application scenario: call can be used when the parameters are clear, and apply can be used to combine arguments when the parameters are unclear
Now give an example
As we all know, onscolll, onresize, etc. are very performance consuming, and numbers are printed when the window is zoomed.
var count = ; window.onresize = function () { count++; console.log(count); }
Retract and retract the browser window size in the Chrome browser, print as follows
This is obviously not what we want. 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 function throttling; of course, add Just use a settimeout() timer,
The first packaging 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 packaging method
Construct a closure and use the 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 and the performance will be better
This returns a function that will not get executed if it is called without interruption. 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 prohibited to use setTimeout in business logic, because many of the usage methods I have seen are problems that are easy to solve, and setTimeout is used 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 the 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 difficult to debug.
I think the correct way to use it is to look at the life cycle (please refer to "About the Life Cycle of Software") and mention instantiation before use.
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!