Throttling and debouncing are two concepts that can be applied to reduce repeated and unnecessary calls to APIs and other functions. They both act (albeit in different ways) to reduce the number of calls made.

In short, we can summarize these concepts as follows:

  • Throttling — applies a rate limit to the number of calls that can happen over a period of time (eg one call per second)
  • Debouncing — waits a set period of time for requests for stop before making a call (and then makes a call using the last request)

Without these, there can be massive performance implications.

If you are writing custom code that will make quick repeated calls — whether to an API or a function — you should consider using throttling or debouncing, to minimize the performance impact.

How NetSuite Commerce Implements These Concepts

One of the core libraries we use is Underscore, and we rely on two methods, appropriately named throttle() and debounce(), to perform throttling and debouncing. It is recommended that you read their documentation first.

Throttling

As a reminder, throttling does not stop calls going through — instead applies a rate limit to them. As a developer, instead of passing the function directly to wherever it is going to be called, you instead pass it wrapped like this:

_.throttle(function, wait, [options])

Where rate is an integer of milliseconds.

So, for example:

_.throttle(function log () {
    console.log('Noisy logs!');
}, 1000);

This will log a message once to the console every second, regardless of how many times it is called during that time.

You can pass in {leading: false} and/or {trailing: false} to prevent the first and last, respectively, calls being made.

If you have a function that tracks mouse movement, for example, and then executes code each time it moves, then you may want to throttle the inputs so that the JavaScript only fires a limited number of times over a set period to minimize the impact on the user’s device. We do this when we customize the loading icon, and when a user resizes the window on the homepage (as we want to show different content to different resolutions).

Debouncing

By default, debouncing will wait for requests to stop being made, before sending one (which is the final one). It is a good fit for API calls because you will typically only one want one call to go through, and for that call to use the user-submitted data from the final request.

To use it, it works like this:

_.debounce(function, wait, [immediate])

The immediate parameter is optional, but if you pass true it will pass the first call and block all subsequent ones (by default, it will block and the first and all succeeding calls, until they stop, and then call using the last request). Using immediate is useful for, for example, submit buttons.

A simple example is:

_.debounce(function log () {
    console.log('This will only show once you stop calling me!')
}, 1000);

So, if this were bound to a method and you were to repeatedly call it, it would wait 1000 milliseconds (ie 1 second) before logging a message to the console.

We use this for typeahead search results: when a user begins typing a keyword to search for, requests for items are automatically sent after the third character has been entered. As the user types out keywords more requests are made, and this could lead to a potentially high number of unnecessary requests. For example, if their final keyword is “jackets”, then “jac”, “jack”, “jacke”, “jacket” would all be requested before they had finished typing — and we don’t need results for those.

So, in this case, we want to debounce the calls: wait until the user has finished typing (or, at least, wait a short delay) and then search using the final keyword they have entered.