Of all the browser events, there is one in particular that deserves your attention: those that tend to be over-triggered.

The Scroll event, for example, is a very easy event to fire over and over again. In fact, not only scroll events, but also resize events, mouse events (such as Mousemove and Mouseover) and keyboard events (such as keyup and KeyDown) may be triggered frequently.

The amount of computation caused by frequent callbacks can cause page jitter and even stutter. To circumvent this, we need some means of controlling how often events are triggered. It was in this context that Throttle and Debounce came into being.

The frequency of event throttling and event stabilization is increasing with the increasing attention paid to front-end performance in recent years. In addition, both of these things exist in the form of closures: they wrap the event’s corresponding callback function, cache the time information as a free variable, and finally control the event’s firing frequency with setTimeout.

Using a piece of code, you can test your mastery of at least two key knowledge points — a favorite interview question at any level.

Throttle: The first person to rule

Throttle’s central idea is that no matter how many callbacks you trigger in a given period of time, I’ll only recognize the first one and respond when the timer ends.

A passenger just got off the plane and needed a car, so he called the airport’s only shuttle bus to pick him up. The driver drove to the airport, thinking it would be worth it to pick up a few more people. I waited ten minutes. So the driver opened the timer, while beckoning the guests behind off and on. During those 10 minutes, passengers disembarking from the next plane can only take this one bus, and at the end of the 10 minutes, no matter how many unpacked passengers are left behind, the bus must leave.

In this story, the “driver” is our throttle valve. He controls the timing of the departure. The “passenger” is the callback task that keeps pouring in because of our frequent manipulation of events, and it needs to accept the arrangement of the “driver”; The “timer” is the time information in the form of free variables mentioned above, which is the basis for the “driver” to decide to start. Finally, the “start” action corresponds to the execution of the callback function.

In summary, throttling is achieved by ignoring subsequent callback requests for a period of time. As soon as a guest calls a bus, the driver will start a timer for him. Within a certain time, all the guests who need to take a bus behind them have to queue up to get on the same bus, and no one can get more buses.

The corresponding actual interaction is the same: every time the user triggers the Scroll event, we start the timer for that triggered operation. For a while, all subsequent Scroll events will be treated as “passengers of a car” — they cannot trigger new Scroll callbacks. The first Scroll callback will not be executed until a certain amount of time has elapsed, and any subsequent scroll callback triggered by a certain amount of time will be ignored by the throttle.

Having understood the general idea, we are now implementing a throttle together

// fn is the event callback we need to wrap, and interval is the threshold of the time interval
function throttle(fn, interval) {
  // last indicates the time when the callback was last triggered
  let last = 0
  
  // return the throttle result as a function
  return function () {
      // Preserve the this context when calling
      let context = this
      // Retain the arguments passed in when the call is made
      let args = arguments
      // Record the time when the callback is triggered
      let now = +new Date(a)// Check whether the difference between the time triggered last time and the time triggered this time is smaller than the threshold of the interval
      if (now - last >= interval) {
      // If the interval is greater than the interval threshold we set, the callback is executedlast = now; fn.apply(context, args); }}}// Throttle the scroll callback
const better_scroll = throttle(() = > console.log('Triggered a scroll event'), 1000)
document.addEventListener('scroll', better_scroll)
Copy the code

Debounce: The last person to call the shots

The central idea is: I will wait for you to the end. No matter how many times you trigger a callback over a given period of time, I only think it’s the last one.

Continue with the driver’s story. This time the driver was more patient. After the first passenger gets on the bus, the driver starts the timer (say ten minutes). If another passenger arrives within 10 minutes, the driver will reset the timer and start waiting for another 10 minutes (delayed). Until a passenger gets on the bus and no new passenger gets on for ten minutes, the driver decides that no one really needs the ride and moves on.

We compare debounce to Throttle: in the logic of Throttle, “the first person is the boss”, it timed only the first passenger and performed a callback when the time was up. According to Debounce, “the last man has the last word”, he sets a new timer for every new passenger.

Based on the above understanding, we write a debounce together

// fn is the event callback we need to wrap, and delay is the wait time for each delayed execution
function debounce(fn, delay) {
  / / timer
  let timer = null
  
  // Return the debounce result as a function
  return function () {
    // Preserve the this context when calling
    let context = this
    // Retain the arguments passed in when the call is made
    let args = arguments
    // Each time an event is triggered, the previous timer is cleared
    if(timer) {
        clearTimeout(timer)
    }
    // Set a new timer
    timer = setTimeout(function () {
      fn.apply(context, args)
    }, delay)
  }
}
// Wrap the scroll callback with debounce
const better_scroll = debounce(() = > console.log('Triggered a scroll event'), 1000)
document.addEventListener('scroll', better_scroll)
Copy the code

Throttle and Debounce are not only good code snippets that we use in our daily development, but they are also important in our front-end interviews. “Understand the code” and “understand the process” are not enough in this section, but it is important to write them into your own projects and experience the performance benefits of throttling and stabilization.