Mixing synchronous and asynchronous requests for serious speed

Hugh Jeremy - Mar 14 '20 - - Dev Community

You know what I'm talking about. Those infuriating websites that present animated grey boxes while they fetch their content asynchronously. For seconds. No one has seconds. Give me the content now!

Draft Rugby is a fantasy Rugby app. It's in early development. Our main feature is the Player Stats page. This page is effectively a glorified table: It allows rapid search and sorting of the ~800 players in the Super Rugby season.

Alt Text

Before today, it loaded pretty quickly. Here's the process:

  1. A browser makes a GET request to /player-stats
  2. Draft Rugby replies with a bunch of HTML, CSS, and JS
  3. The browser runs the JS, which includes an immediate GET request to /api/fantasy/player/list vis the Draft Sport JS library
  4. Draft Rugby replies with a bunch of JSON
  5. The browser eats the JSON and fills the player table

Step 3 is an asynchronous javascript request leading to document manipulation, commonly known as "AJAX". That's nice, because the user can now sort and search the table. Each time they do, more asynchronous requests are made to get them the data they want, and refill the table.

Except it's not always nice, because of the speed of light. In an ideal case, with a client device say, 30 kilometres from the datacenter, there might be 50 milliseconds between the start of step 1 and the start of step 3. In Draft Sport's case it was taking a whopping ~270ms to finish the whole sequence and begin animating the table.

Alt Text

No one has time for 270ms! A user will notice this delay, without question. And it get worse: Your user's visual processing system needs to parse your fancy loading animation while the async request is happening. Then it needs to dump that information and re-parse the actual page content.

Don't do this! It sucks! Let's shift the initial table load back onto the server. Now the sequence looks like this:

  1. A browser makes a GET request to /player-stats
  2. Draft Rugby replies with a bunch of HTML, CSS, and JS, including the content of the player stats table retrieved via Draft Sport Py.
  3. The browser paints everything

From 5 steps to 3. Now:

  • No double round-trip to the datacenter to fetch the initial data
  • No loading animations for the user to parse

What's the tradeoff? It depends on the disposition of your API. Draft Sport API is not the fastest thing in the world, yet - It takes about 50ms to retrieve the player table. That request now blocks the time-to-first-byte, slowing the page delivery down by 50ms.

The synchronous result is still way better. The time until content is fully presented drops from about ~450ms to ~200ms. As Draft Sport API matures and gets faster, that time will drop further, whereas the speed of light isn't going anywhere. And in the real world, your user is not going to be 20ms from your datacenter. The further away they are, faster the synchronous request becomes. Your framework can't outrun the speed of light!

Conclusion? Don't be afraid to hold up returning your first byte with a server-side API request. If you know what data the client wants, your overall time to displayed content will probably be significantly lower than if you return it asynchronously via an AJAX request.

-Hugh

. . . . . . . . . . . . . . . . .
Terabox Video Player