Debounce and throttle(防抖和节流)

129 阅读2分钟

Debounce and throttle are two similar (but different!) techniques to control how many times we allow a function to be executed over time. 控制函数调用的频率

Debounce

We are giving ourselves a layer of control between the event and the execution of the function. Remember, we don’t control how often those DOM events are going to be emitted. It can vary.

问题: In 2011, an issue popped up on the Twitter website: when you were scrolling down your Twitter feed, it became slow and unresponsive. John Resig published a blog post about the problem where it was explained how bad of an idea it is to directly attach expensive functions to the scroll event.

早期解决方式: The suggested solution by John (at that time, five years ago) was a loop running every 250ms, outside of the onScroll event. That way the handler is not coupled to the event. With this simple technique, we can avoid ruining the user experience.

The Debounce technique allow us to “group” multiple sequential calls in a single one.

image.png

电梯的例子:Imagine you are in an elevator. The doors begin to close, and suddenly another person tries to get on. The elevator doesn’t begin its function to change floors, the doors open again. Now it happens again with another person. The elevator is delaying its function (moving floors), but optimizing its resources.

Leading edge: You may find it irritating that the debouncing event waits before triggering the function execution, until the events stop happening so rapidly. Why not trigger the function execution immediately, so it behaves exactly as the original non-debounced handler? But not fire again until there is a pause in the rapid calls.

image.png

//debouce helper
const debounce = (func, delay = 1000) => {
  let timeoutID;
  return (...args) => {
    //clear previous timeout
    if (timeoutID) {
      clearTimeout(timeoutID);
    }
    //set new timeout
    timeoutID = setTimeout(() => func.apply(null, args), delay);
  };
};

Throttle

Don’t allow to our function to execute more than once every X milliseconds. 在一段时间间隔里,只允许函数执行一次,控制的是时间

The main difference between this and debouncing is that throttle guarantees the execution of the function regularly, at least every X milliseconds.

const throttle = (fn, delay) => {
    let end = 0
    return (...args) => {
        const now = new Date()
        if(now - end < delay) {
            return
        }
        end = now
        return fn(...args)
    }
}

Throttling Examples

Infinite scrolling

A quite common example. The user is scrolling down your infinite-scrolling page. You need to check how far from the bottom the user is. If the user is near the bottom, we should request via Ajax more content and append it to the page.

Here our beloved _.debounce wouldn’t be helpful. It only would trigger only when the user stops scrolling.. and we need to start fetching the content before the user reaches the bottom.
With _.throttle we can warranty that we are checking constantly how far we are from the bottom.