Debouncing makes it so a function can only be executed after a certain amount of time since it was last invoked. For example, “only execute this function if it has been 1000 milliseconds since it was last invoked.”
A common use case for debouncing is in search bars. We don’t want to make expensive http requests while the user is still typing their query, so we debounce the requesting function and only invoke it once the user has stopped typing.
Here was my first attempt at implementing debounce.
At first glance, this seems to work as expected.
After taking a look at underscore’s implementation of the same function, I realized that I had made a critical oversight. Namely, what happens when a debounced function is used as a method on an object?
That’s not right! Let’s figure out what’s going on here.
My first attempt to solve this bug was to get the context when the debounced function is invoked and bind that to the original function via apply.
This is an awesome feature, usually. In conforms more to our intuition about how `this` should behave. But we cannot forget about `this` just because we have arrow functions, and this is a perfect example of why.
`this` is still bound to the global scope in my updated function.
When I call `debounce` on `sayHello`, the creation context is the global scope, since debounce is a free-function invokation. Therefore, the arrow function returned from debounce is also bound to the global scope.
We specifically want `this` to be set at call-time, so an arrow function is the wrong tool entirely. By switching from an arrow function to a traditional anonymous function, we obtain a fully working solution.
const sayHello = () => console.log('My name is', this.name)
Keep this advice this in mind when using 3rd-party libraries as well. D3 and Mocha come to mind as libraries that can behave unexpectedly if you pass arrow functions as callbacks.
Arrow functions are great, but you need to know how they work, when to use them, and when to avoid them.