selfie of Kenton

Kenton Vizdos

i make cool things in go. this is my dev log. note: it's not a technical masterpiece, I just like writing (sometimes poorly) about what I learn!

Real-Time Search Doesn't Mean Real-Time Requests

Why Real-Time Feels Slow #

Have you ever searched anything in "real-time"?

Humans type fast (sometimes).

Sending a request on every keystroke is wasteful, slow, and costly. Developers need a solution that feels responsive yet intelligently waits until the user pauses.

Introducing... debouncing & aborts.

What Is Debouncing? #

Debouncing is the solution to many developers' problems. Commonly used in real-time search fields, debouncing prevents sending tens of requests per query. Debouncing accomplishes this by measuring the time between keystrokes and only "officially" sending a request after ~200-400ms have passed.

Without debouncing, a network may look like:

On the other hand, if the search was debounced and the user types quickly:

Since the user typed "test" with less than 200ms between each keystroke, the debounce timer kept resetting. Only after typing stopped for 200ms did the final request fire, saving three unnecessary fetches.

Debounce comes in three distinct flavors, each tuned to when you want the callback to fire:

In the wild, I found a few companies where debouncing quietly saves bandwidth:

While debouncing can provide a robust solution for many search solutions, Abort Signals provide an extra layer to beef up performance.

What Is an Abort Signal? #

As of March 2019, all major browsers can now cancel fetch() requests. (wow, that took a while! IE + Opera Mini not included)

This means that, combined with debouncing, servers can reduce load and prematurely cancel old requests as soon as a new query comes in. In Go, this is as simple as passing the request.Context() into your database driver of choice: the request-- propagating all the way to the database-- is canceled instantly. No more wasted ops, woot!

A few real-life use cases of pure abort signals include:

Some places don't do either!

UX Benefits #

Users feel instant feedback without burning bandwidth. Primarily, they can interact with systems that "feel" real-time, yet consider their network usage / CPU time. These techniques also help to reduce "flickering" that could occur when multiple requests come back at once (search YouTube on a slow connection, eesh!).

Both debouncing & aborts can make use of heavy client-side caching to provide a seamless search experience.

When to use Debouncing & Aborts #

While I've gone on to talk about search so far, debouncing also has a few other nice use cases:

Aborts, on the other hand, are usually used with events involving network calls (e.g. fetch()).

How I'd design a Search System #

I don't run billion-dollar companies. I'd rather not be like YouTube and Amazon and query every search: that sounds pricey. After researching how a few sites do it, I think my approach would be:

I may allow more than 1 request in flight. If I did it, I'd need to pay extra attention to making sure the latest request accurately resolved in the search.

Next post that actually implements this coming soon!