A detailed explanation of throttle_javascript techniques in JavaScript throttling function

Source: Internet
Author: User
Tags closure

First, let's find out what throttle is.                            

1. Define

If you tighten the faucet until the water is flowing in the form of a drop, you will see that every once in a while, there will be a drop.

That is to say, pre-set an execution cycle, execute the action when the time of the call is greater than or equal to the execution cycle, and then move on to the next new cycle.

Interface Definition:

* Frequency control returns function Continuous call, the action execution frequency is limited to the secondary/delay
* @param delay {Number} delay time, the unit millisecond
* @param action {function} request correlation function, the actual application function required to be invoked
* @return {function} to return the client call function
/throttle (delay,action)

2. Simple implementation

var throttle = function (delay, action) {
 var last = 0return function () {
 var curr = +new Date ()
 if (Curr-la St > Delay) {
  action.apply (this, arguments) last
  = Curr 
 }
 }
}

Let me explain this throttle function carefully.

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 Method
 */
   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 the previous variable is similar to that of a timer, which records the previous identity and must be a relative global variable
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, simply: The last time the next one 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 Performance is: In the process of page scrolling (can not stop) TESTFN will not be called, until the stop will be called once, that is, the implementation of the throttle inside the last settimeout, the effect as shown:


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

As shown above, the effect we are trying to achieve has been introduced and presented as an example, looking to help friends in need. Some of the following auxiliary optimization readers can make their own pondering, such as: function this point, return value save, and so on. Anyway, it feels so good to understand this process.

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.