Ramble: I originally intended to summarize anti-vibration and throttling in one article, but I found it interesting to write about it. So the preparation will be divided into 3-4 articles to write, a separate anti-shake and throttling implementation, and then to share the well-known library source code. Today first with crooked horse to see the realization of anti – shake. Other content please look forward to ~!


Crooked teacher: “ma classmate, anti – shake and throttle you know? Get up and speak.”

Ma classmate: “teacher, I don’t know ah, have never heard of.”

Crooked teacher: “ok, that today we will tell first to defend shake. Start with the basic concepts and usage scenarios.

A concept,

The concept of debounce and throttling is not unique to JS. They are two concepts of different control over continuous calls to a function. Today we are going to introduce anti-shake.

The purpose of anti-shaking is to prevent the user from accidentally executing the function more than once. For example, some users like to use double click when they click, or just tap two times in a row, which may cause some unexpected problems.

It is possible to perform the related handler functions only if the same event is not triggered again after a certain amount of time.

It’s like when you go to the market to buy vegetables, and you go to a stall and start to pick out vegetables, and you pick up bag after bag and put it in front of the stall owner, and the stall owner doesn’t pay for every bag, but he waits and asks you, “Do you want anything else?” I will check out after you confirm no more.

You can check my regular written by crooked horse this demo unrestricted function calls and image stabilization (throttle) after visual contrast, complete demo address is as follows: codesandbox. IO/s/yibubupia… .

Ii. Functions & Application scenarios

Before the concrete implementation, we first have a brief understanding of the functions of anti-shake and throttling and which businesses will use them.

Anti-vibration and throttling (including it first) mainly bring us the following benefits:

  1. Optimize user experience: timely feedback, avoid UI rendering jam and browser stutter
  2. Improve page performance: avoid page rendering lag, reduce server stress, and prevent malicious triggering

The application scenarios of anti-shake are as follows:

  1. Input box content association –> timely feedback, reduce server pressure
  2. window.resize–> Avoid UI rendering blocking and browser stalling
  3. Submit forms –> Reduce server stress and prevent malicious triggers

Crooked teacher: “concept we introduce to this, below we come to see how should realize.”

Three, how to achieve anti-shake

“Anti-shake can be achieved through a timer, through setTimeout to specify a certain time after the execution of the processing function, if the event is triggered again before this time, the timer will be cleared, restart the time.”

function debounce(fn, wait{

  let timerId = null;

  return function(. args{

    if (timerId) clearTimeout(timerId);

    timerId = setTimeout((a)= > {

      fn.call(this, args);

    }, wait);

  };

}

Copy the code

Ms Askew: “That’s the basic implementation of Debounce, everyone?

Ma Niuyang: “I understand.”

Crooked teacher: “good, below we come step by step expand. Ma, on this basis, let you to implement the first trigger immediately execute a function, how will you achieve?”

Ma classmate: “teacher, what scene just need to be carried out for the first time?”

Crooked teacher: “😓 this you don’t care, demand is such now. How would you do that?”

Classmate Ma: “Oh, let me see. If the timerId is null, just execute it.

function debounce(fn, wait) {

  let timerId = null;

return function(... args) {

- if (timerId) clearTimeout(timerId);

+ if (timerId) {

+ clearTimeout(timerId);

+ } else {

+ // First direct call to the function

+ fn.call(this, args);

+}

    timerId = setTimeout(() => {

      fn.call(this, args);

    }, wait);

  };

}

Copy the code

Crooked teacher: “very good, so can really achieve the first trigger immediately execute. But if, after the normal delay execution (debmentioning execution), it will trigger again after a time interval, will the first trigger be executed?”

Horse classmate“Well, let me see. I don’t think it’s going to happen. becausetimerIdIt’s always going to be the same value as last time. Like the picture below, there should be a trigger in the middle. If you want to implement this feature, you can delay the execution each timetimerIdSet to null.”

function debounce(fn, wait) {

  let timerId = null;

return function(... args) {

    if (timerId) {

      clearTimeout(timerId);

    } else {

      fn.call(this, args);

    }

    timerId = setTimeout(() => {

      fn.call(this, args);

+ timerId = null;

    }, wait);

  };

}

Copy the code

Crooked teacher: “quite good, a little on, so really ok. But in this case, if the interval between the first delayed firing and the subsequent new firing is less than the time interval we set. Does it trigger another one? What if you want to keep the trigger interval no smaller than the wait event interval?”


Ma: “Uh (⊙o⊙)… I don’t know, Sir. I think you’re giving me a hard time. Why don’t you call them?”

Crooked teacher: “ha ha, don’t say so, the teacher is exercising your thinking ability. A lazy execution idea similar to the one above can be used here. The first firing is determined by whether the timerId is null, and to avoid premature firing of the first execution after delayed execution, simply delay the previous null operation as well. As follows:

function debounce(fn, wait) {

  let timerId = null;

return function(... args) {

    if (timerId) {

      clearTimeout(timerId);

    } else {

      fn.call(this, args);

    }

    timerId = setTimeout(() => {

      fn.call(this, args);

+ setTimeout(() => {

        timerId = null;

+ }, wait);

    }, wait);

  };

}

Copy the code

Crooked teacher: “that horse classmate, you feel so can have what problem have not?”

Ma: (think for a moment…) I don’t think there’s any problem. After all, it was you who gave the plan.”

Crooked teacher: “not, so still have a problem.”

Ma classmate: “teacher, you this is an interlocking set ah… One ring at a time. What’s the problem?”

Bad teacher: “We have just set the timer delay empty, there is no clear operation, when so many consecutive triggers, cancel the operation of the actually calculated according to the time for the first time the trigger delay, this will lead to the first execution in later suddenly trigger, and then performed for the first time in advance and can cause normal delay execution function problem (not clear the timer), Causes it to execute as it did the first time. As shown in the picture below:


So, here we only need to clear the timerId, also cancel the delay blank line.

function debounce(fn, wait) {

  let timerId = null;

+ let leadingTimerId = null;

return function(... args) {

    if (timerId) {

      clearTimeout(timerId);

+ clearTimeout(leadingTimerId);

    } else {

      fn.call(this, true, args);

    }

    timerId = setTimeout(() => {

      fn.call(this, false, args);

- setTimeout(() => {

+ leadingTimerId = setTimeout(() => {

        timerId = null;

      }, wait);

    }, wait);

  };

}



Copy the code

Crooked teacher: “now horse classmate, do you feel still have a problem?”

Ma classmate: “teacher, I think there should be a problem.”

Crooked teacher: “that have what problem?”

Ma classmate: “er, teacher, I guess, actually don’t know… Tell me more.”

Crooked teacher: “know to play clever, nevertheless really still existence problem. Look at the picture below.”


If only one event is triggered (you can change the mousemove in the demo to Click and try again), the first trigger will be executed, but no other trigger will follow, and another delayed trigger will be triggered. What do you do if you want to avoid the problem that if the first trigger is not triggered again, there is no delay?”

Crooked teacher: “ma classmate need not hide, this time don’t ask you. The teacher said directly.”

function debounce(fn, wait{

  let timerId = null;

  let leadingTimerId = null;

  return function(. args{

    if (timerId) {

      clearTimeout(timerId);

      clearTimeout(leadingTimerId);



      timerId = setTimeout((a)= > {

        fn.call(this.false, args);

        leadingTimerId = setTimeout((a)= > {

          timerId = null;

        }, wait);

      }, wait);

    } else {

      fn.call(this.true, args);

      // A special value introduced to solve the problem that triggers both the first and the delayed trigger only once

      timerId = - 1;

    }

  };

}

Copy the code

Crooked teacher: “good, today speak so much, everybody remember after class homework. Is there a problem with that? You can leave a comment.”

conclusion

I know this article seems to be confusing to read, and you’ll notice that it doesn’t seem to work the way you’d expect anti-shock to work. But so what? Most of the time, we implement the functionality we need based on the specific usage scenario, so it’s important to know how to implement it, but also to adapt.

And finally you know how to implement Debounce and what the potential pitfalls are, right?


Related links have been lit up in the skill tree, welcome to check.

Documentation link: mubu.com/doc/4VGWywo… Password: Slanting code line blank


If you like, please scan the code to follow my public account. I will accompany you to read regularly and share some other front-end knowledge.