Debouncing And Throttling

Gaurav Rajput
3 min readSep 14, 2024

--

Throttling and Debouncing are techniques used to control the rate at which a function is executed. They are handy when dealing with events like button clicks, network requests, or user input that can be triggered multiple times in quick succession.

Let's understand the difference between them:-

Throttling

Imagine you’re making an API request every time a button is clicked. If the network is slow or the server is down, users may repeatedly click the button, triggering multiple requests in a short time. This can overwhelm the server and degrade the user experience. How can we address this? One approach is to limit the number of API calls within a specific time frame to avoid sending too many requests in a short period. This technique is known as Throttling.

This way, even if the button is clicked multiple times, the API requests are sent at controlled intervals.

Let’s see by code how can we implement this:

import kotlinx.coroutines.*
import kotlin.system.measureTimeMillis

fun throttle(delayMs: Long, action: () -> Unit): () -> Unit {
var lastExecutionTime = 0L
return {
val currentTime = System.currentTimeMillis()
if (currentTime - lastExecutionTime >= delayMs) {
lastExecutionTime = currentTime
action()
}
}
}

fun main() {
val throttledAction = throttle(1000L) {
println("Action executed at ${System.currentTimeMillis()}")
}

repeat(5) {
throttledAction() // Only the first call within 1000ms will execute
Thread.sleep(300L) // Sleeping for 300ms before the next call
}
}

The above function will execute 2 times one for the first action and the other for the last action as till then 1000L milli seconds have been passed.

Ok Now let's understand what is Debouncing.

Debouncing

Debouncing ensures that a function is called only after a specified period of inactivity. If the event is triggered multiple times, the function is only called once the specified delay period has passed without any additional event triggers.

For instance, when typing in a search box, you might want to wait until the user has stopped typing for 500ms before sending a network request to fetch search results.

I guess it self self-explanatory let's see how it will be implemented as a function.

import kotlinx.coroutines.*

fun debounce(delayMs: Long, action: () -> Unit): () -> Unit {
var debounceJob: Job? = null
return {
debounceJob?.cancel()
debounceJob = GlobalScope.launch {
delay(delayMs)
action()
}
}
}

fun main() = runBlocking {
val debouncedAction = debounce(1000L) {
println("Action executed at ${System.currentTimeMillis()}")
}

repeat(7) {
debouncedAction() // Only the last call will be executed after 1000ms
delay(300L) // Sleeping for 300ms between each call
}

delay(1500L) // Waiting for debounce to complete
}

It does not matter here how many times this repeat block you are executing, only the last call will be executed after 1000L of inactivity.

Let’s see by diagram as well

Only the last action will be executed after an inactivity of 1000L milli sec in the above case.

I hope this explanation clarifies the difference. If it did, feel free to give it a clap! If not, let me know how I can improve it, or share your feedback in the comments.

--

--