JavaScript throttling function Throttle detailed _javascript skills

Source: Internet
Author: User
Tags closure

In the browser DOM event, there are some events that can be triggered uninterrupted by the user's actions. For example: Resize browser window size (resize), browser page scrolling (scroll), mouse Movement (MouseMove). In other words, when the user triggers these browser operations, if the script is bound to the corresponding event processing method, this method will not stop triggering.

This is not what we want, because sometimes if the event processing method is large, DOM operations such as complex, and constantly trigger such events will cause loss of performance, resulting in user experience degradation (UI reflection slow, browser card Deng). So we usually add the logic of deferred execution to the corresponding event.

In general, we use the following code to implement this feature:

 var COUNT = 0;
function Testfn () {console.log (count++);}
Browser resize/
/1. Clear before Timer
//2. Add a timer to allow the real function testfn to delay 100 milliseconds to trigger
window.onresize = function () {
 var timer = null;
 Cleartimeout (timer);

 Timer = settimeout (function () {
  testfn ();
 };
 

Careful students will find that the above code is actually wrong, this is a novice will make a problem: the SetTimeout function return value should be kept in a relative global variable, otherwise each time the resize will produce a new timer, so that we can not reach the effect of our hair

So we modified the code:

 var timer = null;
Window.onresize = function () {
 cleartimeout (timer);
 Timer = settimeout (function () {
  testfn ();
 };
 

This time the code is normal, but there is a new problem--a global variable timer is created. This is something we don't want to see, if this page has other features called timer different code is a conflict. To solve this problem we have to use a language feature of JavaScript: closure closures. Relevant knowledge readers can go to MDN to understand, after the transformation of the code is as follows:

 /**
 * Function Throttle Method
 * @param function fn Delay call functions
 * @param number delay delay how long
 * @return Function delay Execution
 /
var throttle = function (FN, delay) {
 var timer = null;

 return function () {
  cleartimeout (timer);
  Timer = settimeout (function () {
   fn ();
  }, delay);
 }
;
Window.onresize = Throttle (TESTFN, 200, 1000); 

We use a closure function (throttle throttling) to put the timer inside and return the delay processing function, so that the timer variable is not visible externally, but the internal delay function can also access the timer variable when triggered.

Of course, this type of writing for beginners is not easy to understand, we can change a way to understand the wording:

 var throttle = function (FN, delay) {
 var timer = null;

 return function () {
  cleartimeout (timer);
  Timer = settimeout (function () {
   fn ();
  }, delay);
 }
;

var f = throttle (testfn, MB);
Window.onresize = function () {
 f ();
}; 

The main thing to know here is that the function returned after throttle is called is the real onresize that needs to be invoked when triggered.

Now it seems that this approach is almost perfect, but not in practice. As an example:

If the user keeps resize the browser window, the deferred handler function is not performed at once

So we're going to add a function: When the user triggers the resize, it should be triggered at least once in a certain period of time. Since it is a certain period of time, then this criterion can take the current number of milliseconds, each time the function call to the current time and the last call time subtraction, and then judge the difference if more than a certain period of time Directly trigger, or walk timeout delay logic.

The following code needs to be noted:
The function of a 1.previous variable is similar to that of a timer, which records the previous identity and must be a relative global variable
2. If the logic flow is "trigger at least once" logic, then the function call completes the need to reset the previous to the current time, in simple terms: relative to the next time the last time is actually the current

/**
 * Function Throttle Method
 * @param function fn Delay call functions
 * @param number delay delay how long
 * @param number atleast at least a long time to trigger 
   * @return Function Delay Execution
 * *
var throttle = function (FN, delay, atleast) {
 var timer = null;
 var previous = null;

 return function () {
  var now = +new Date ();

  if (!previous) previous = now;

  if (now-previous > atleast) {
   fn ();
   Resets the previous start time to this end time
   previous = now;
  } else {
   cleartimeout (timer);
   Timer = settimeout (function () {
    fn ();
   }, delay);
  }
 }
; 

Practice:
We simulate a scenario in which a window is scroll, that is, when the user scrolls down the page we need to throttle to execute some methods, such as calculating DOM position and so on, which require continuous manipulation of DOM elements.
The complete code is as follows:

 <!
DOCTYPE html>  

We use two case to test the effect by adding at least triggering atleast parameters and not adding:

 Case 1
window.onscroll = throttle (TESTFN);
Case 2
window.onscroll = Throttle (TESTFN, 200, 500); 

Case 1 behaves as follows: In the process of page scrolling (cannot stop), TESTFN will not be invoked until it is stopped, which means that the last settimeout in the throttle is executed, as shown in the image (see the original GIF):


Case 2 behaves as follows: In the process of page scrolling (which cannot be stopped) the first time the TESTFN delays 500ms execution (from at least the latency logic), and then executes at least once every 500ms, as shown

So far, the effect we want to achieve has been basically done. Some of the following auxiliary optimization readers can make their own pondering, such as: function this point, return value save, and so on.

The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.