Function throttling, simply put, makes a function unable to be called continuously within a very short time interval. Only when the last function has been executed after the time interval specified by you can the next call to the function be made.
The principle of function throttling is quite simple. I guess everyone has thought of it, that is the timer. When I trigger a time, first setTimout to delay the event for a while before execution. If the event is triggered again within this time interval, then we clear the original timer and then setTimeout a new timer to delay the execution for a while, that's it.
In the following scenarios, the following scenarios often perform heavy behaviors such as DOM operations and resource loading, causing UI to pause or even browser crashes.
1. Resize and scroll events of window object
2. Mousemove event during dragging
3. Mousedown and keydown events in shooting games
4. Keyup events that are automatically completed by text input
In fact, for the resize event of window, the actual requirement is to stop changing the size n milliseconds and perform subsequent processing; while most other events require subsequent processing at a certain frequency. There are two solutions to these two needs, debounce and throttle.
throttle and debounce are two solutions to solve the problem of request and response speed mismatch. The difference between the two lies in choosing different strategies.
Execute functions at intervals such as throttle.
If the event is triggered again within the debounce interval t, the timer will be re-timed until the stop time is greater than or equal to t.
1. Simple implementation of throttle function
function throttle(fn, threshhold, scope) { threshhold || (threshhold = 250); var last, timer; return function () { var context = scope || this; var now = +new Date(), args = arguments; if (last && now - last + threshhold < 0) { // hold on to it clearTimeout(deferTimer); timer = setTimeout(function () { last = now; fn.apply(context, args); }, threshhold); } else { last = now; fn.apply(context, args); } };}Calling methods
$('body').on('mousemove', throttle(function (event) {console.log('tick');}, 1000));2. Simple implementation of debounce function
function debounce(fn, delay) { var timer = null; return function () { var context = this,args = arguments; clearTimeout(timer); timer = setTimeout(function () { fn.apply(context, args); }, delay); };}Calling methods
$('input.username').keypress(debounce(function (event){// do the Ajax request}, 250));3. Simple packaging implementation
/** * throttle * @param fn, wait, debounce */var throttle = function ( fn, wait, debounce ) { var timer = null, // timer t_last = null, // last time set, // context args, // parameter diff; // time difference return funciton () { var curr = + new Date(); var context = this, args = arguments; clearTimeout( timer ); if ( debounce ) { // If it is debounce timer = setTimeout( function () { fn.apply( context, args ); }, wait ); } else { // If it is throttle if ( !t_last ) t_last = curr; if ( curr - t_last >= wait ) { fn.apply( context, wait ); context = wait = null; } } }}/** * debounce * @param fn, wait */var debounce = function ( fn, wait ) { return throttle( fn, wait, true );}Summary: These two methods are suitable for some events that will be triggered repeatedly, such as: mousemove, keydown, keyup, keypress, scroll, etc.
If you only bind native events and do not control them, the browser will be stuttered and the user experience will be poor. In order to improve js performance, it is recommended to use function throttling or function debounce to control when using the above and similar events.
4. Analysis of source code related to underscore v1.7.0
1. _.throttle function
_.throttle = function(func, wait, options) { var context, args, result; var timeout = null; // Timer var previous = 0; // Time last triggered if (!options) options = {}; var later = function() { previous = options.leading === false ? 0 : _.now(); timeout = null; result = func.apply(context, args); if (!timeout) context = args = null; }; return function(){ var now = _.now(); // Whether to execute if (!previous && options.leading === false) previous = now; // Here is a concept of remaining: how long is the time left to execute the event var remaining = wait - (now - previous); context = this; args = arguments; // remaining <= 0 Considering that the event is retried after the event is stopped or // When the wait is exactly different, the event will be triggered immediately// remains > wait does not take into account the corresponding scenario// Because now-previous is always positive and not 0, then // remaining will always be smaller than wait, and there is no greater than wait// It is estimated that it is safe, and this situation will also be executed immediately if (remaining <= 0 || remaining > wait) { if (timeout){ clearTimeout(timeout); timeout = null; } previous = now; result = func.apply(context, args); if (!timeout) context = args = null; // Whether to track} else if (!timeout && options.trailing !== false){ timeout = setTimeout(later, remaining); } return result; };};As can be seen from the above, underscore has considered more situations: options.leading:
The first time is executed, the default is true, which means that the first time will be executed. The first time execution options.trailing is disabled: the last time is executed, the default is true, which means that the last time will be executed. The last time is passed {trailing: false} means that the last time is not executed. The so-called first time is whether the event is executed first. When the event is just started, whether the event should be triggered first. If you want, previous=0, and remaining is negative, the so-called last time whether the function is executed, is immediately called after the event is over. This method is triggered the last time. If you want to execute, a timer is set, that is, it must be executed once after the event is over. remianing > wait means that the client time has been modified.
2. _.debounce function
_.debounce = function(func, wait, immediate) { // immediate default is false var timeout, args, context, timestamp, result; var later = function() { // When the function returned by _.debounce is called multiple times during the time interval specified by wait, the value of timestamp will be continuously updated, resulting in the last < wait && last >= 0 always being true, thus constantly starting a new timer for delay execution func var last = _.now() - timestamp; if (last < wait && last >= 0) { timeout = setTimeout(later, wait - last); } else { timeout = null; if (!immediate) { result = func.apply(context, args); if (!timeout) context = args = null; } } }; return function() { context = this; args = arguments; timestamp = _.now(); // When the method is called the first time and immediately after the time interval specified by wait, the timer is started to call the func function if (!timeout) timeout = setTimeout(later, wait); if (callNow) { result = func.apply(context, args); context = args = null; } return result; };};I think the wonderful thing about the implementation of _.debounce is to start the timer recursively instead of adjusting the delay execution of calling func functions by calling clearTimeout.
The above is the JavaScript performance optimization function throttling and debounce function that the editor introduced to you. I hope it will be helpful to you. If you have any questions, please leave me a message and the editor will reply to you in time. Thank you very much for your support to Wulin.com website!