The tortoise and the hare (fast is not always good, slow is not always bad)

I believe this is a familiar example. The rabbit runs fast, which is the advantage of his victory, but it is also the “fast” that makes it proud of the idea, causing him to miss the chance of victory by underestimating the enemy.

The tortoise runs slowly, but he is very modest, one step at a time, steady forward seize the opportunity to win!

The tortoise and the Hare in the browser

Onscroll onInput resize onKeyUp keyDown… So when it comes to this, should we make it “execute fast like a rabbit “, or should we make it” move steadily like a turtle “? However, if it is executed quickly, it may cause page stalling in larger projects or lower versions of the browser and affect the user experience (if you do not understand, please Google the browser rendering process + redraw, reflux)! Moving steadily forward like a turtle is much less likely to cause stutter, and has little impact on the user experience! So we might as well forge ahead!

So how do you execute steadily?

Optimizing high Frequency Events reduces code execution frequency

So how do you reduce the frequency of code execution?

Lower frequency code execution “throttle” (throttle) | | debounce (offer)

You’re throttle and debounce.

Please remember two concepts first: throttling > interval fixed time execution, anti – shake > you do not stop I will not execute. Please remember, remember, remember!! Don’t confuse these two words any more !!!!

You’re throttle.

So let’s go straight to the code, and let’s look at a simple version that’s easy to understand.

functionthrottle(fn, threshhold=150) { var timeout; Var start = new Date; // Start timereturn function() { var context = this, args = arguments, Curr = new Date() -0 clearTimeout(timeout)// Always kill the event callbackif(curr - start >= threshhold){fn. Apply (context, args) start = currelse{// Enable the method to execute once after it has been removed from the event (e.g., the last time a button is clicked, the callback function will not be executed if it is smaller than threshhold, so this timer will ensure that the last time is executed regardless of the interval)setTimeout(function(){
       fn.apply(context, args) 
    }, threshhold);
   }
 }
}
var logger = throttle(function(e) { console.log(e.pageX, e.pageY) }); // bind listener document.querySelector("#btn").addEventListener('click',logger);
Copy the code

Let’s take a look at UnderScore for encapsulation of throttle

function throttle(func, wait, options) {;let args, context, previous = 0, timeout;
      let later = function() {// Last timer callback func.apply(context, args); args = context = null }let throttled = function () {
        args = arguments;
        context = this;
        letnow = Date.now(); // The current timelet remaning = wait - (now - previous);
        if (remaning <= 0) {
          if(timeout) {// Clear the timer for multiple clicks in a row, since it is not the last click, the timer is retained only after the last click clearTimeout(timeout); timeout = null; } func.apply(context, args); previous = now; }else if(! timeout && options.trailing ! = =false) {// If we do not follow the trailing timer, it is undefined, which is not flasesetTimeout(later, remaning); }}return throttled;
    }
    function logger() {
      console.log('logger'); } // Parameter trailiing: to enable the callback method to execute after the last event is triggered btn.addeventListener ('click', throttle(logger, 1000, { trailiing: true})); // leading: not executing the callback immediately after the first eventfunction throttle(func, wait, options) {
      let args, context, previous = 0, timeout;
      let later = function () {
        previous = options.leading === false? 0 : Date.now(); Func. Apply (context, args); args = context = null }let throttled = function () {
        args = arguments;
        context = this;
        let now = Date.now();
        if(! previous && options.leading ===false) previous = now; // Step 1: Remaning must be greater than 0 to make it goelse if, that is, to define timer delay processing events.let remaning = wait - (now - previous);
        if (remaning <= 0) {
          if (timeout) {
            clearTimeout(timeout);
            timeout = null;
          }
          func.apply(context, args);
          previous = now;
        } else if(! timeout && options.trailing ! = =false) {
          timeout = setTimeout(later, remaning); }}return throttled;
    }
    function logger() {
      console.log('logger');
    }
    // btn.addEventListener('click', throttle(logger, 1000, { trailiing: true})); // Delay the first click is not valid btn.addeventListener ('click', throttle(logger, 1000, { leading: false }));
Copy the code

Here is my own simple rewrite of the source code for Throttle in UnderScore. If you do not understand, please private message me.

Debounce

Anti – shake implementation is very simple

function debounce(func,wait) {
      let timeout;
      return function() { clearTimeout(timeout); // If there is a timer, clear it first. Always ensure that there is only one timer timeout =setTimeout(() => {
          func.apply(this,arguments);
          timeout = null;
        }, wait); }}function logger(e) {
      console.log('logger');
    }
    btn.addEventListener('click', debounce(logger,1000));
Copy the code

However, there is a bug in this, which is that we have to wait a long time for the first click to see the effect, and sometimes we want to click the effect immediately.

Here’s a look at the encapsulation of debounce by UnderScore

function debounce(func,wait,immediate) {
      let timeout;
      return function () {
        clearTimeout(timeout);
        if(immediate){
          letcallNow = ! timeout; // The first time you click timeout is undefinedtrue, the next line will be executed, and the second time you click it, timeout will not be empty and the original logic will not be executed. This also achieves the effect of clicking the first time to execute immediately.if(callNow) func.apply(this, arguments);
        }
        timeout = setTimeout(() => {
          func.apply(this,arguments);
          timeout = null;
        }, wait); }}function logger(e) {
      console.log('logger',e); } // The third argument is the first to trigger btn.addeventListener ('click', debounce(logger,1000,true));
Copy the code

UnderScore above is a basic implementation of throttling and stabilization, and of course a cancel method, but that is simple enough to see for yourself

Link: github.com/jashkenas/u…

Article to be continued…

ToDo :(1) explain the idea of the article again, with some gifs and examples step by step to achieve the anti-shake throttling

ToDo :(2) implement the anti-shake throttling of lodash step by step

PS: New Year at home fat, write a little general also hope big guys forgive