⚠️ I'm actively rebuilding this site in Astro incrementally, and not waiting til I'm done! Something something work in public. See previous version.

Amberley Romo

What is Asynchronous JavaScript

When people talk about asynchrony in JavaScript, what do they mean?

First, a real-world example of an asynchronous process (summarized here, and originally here).

Imagine you walk into a coffee shop to get a latte. If they’re busy, perhaps you wait in line. When it’s your turn, you place your order with the cashier, and pay for the drink. The cashier writes your order — maybe even your name — on a coffee cup, and places it behind the empty (not yet fulfilled) cup of the person who ordered before you. Perhaps the shop is quite busy and there are ten cups ahead of yours. That queue of yet-unfilled coffee cups allows for the separation of the cashier (processing and queuing orders) and the barista (fulfilling orders based on the information supplied by the cashier). This queuing process results in increased efficiency and output. Additionally, perhaps some drinks take more time than others, and they aren’t necessarily ready to be delivered to the customer in order of purchase — drinks go out when they’re ready, rather than in order of request. (The original source expands on the metaphor and is quite interesting). This is an example of asynchronous, non-blocking behavior.

JavaScript is single-threaded — it processes one command at a time. In the browser, that thread handles our JavaScript and UI processes. That means that, if our programs processed synchronously, long-running tasks — like a server request — would block all other processes.

The way we manage that problem is with asynchronous code. In the context of the single-thread, that means that instead of waiting for that long-running task to complete before continuing on in the queue, we keep on marching through the event loop and wait for the long-running task to complete — and provide notification when it’s done, and handle the response and do something with it.

So wait, what is the event loop, and how do we magically know when our long-running task is complete?

JavaScript runtimes contain a message queue which stores a list of messages to be processed and their associated callback functions. These messages are queued in response to external events (such as a mouse being clicked or receiving the response to an HTTP request) given a callback function has been provided. If, for example a user were to click a button and no callback function was provided – no message would have been enqueued. (Source)

Sidenote: My favorite resource on understanding the event loop is Philip Roberts’ talk, “What the heck is the event loop anyway?”, from JSConf EU 2014. Highly recommend taking the time to watch, it’s well worth it.

As we make demands of our environment (UI changes, fetching data, etc.), those demands get pushed into the queue, and executed in order. Lets take our anonymous ‘long-running task’ from earlier and say it’s an AJAX request to retrieve some data. That initial request is pushed into the queue and executed. But the data is not instantaneously retrieved and available to us, because AJAX requests don’t execute synchronously. If they did, we could do something like this:

var newData = $.get('http://someresource.com')
console.log('are you my data? ', newData) //=> not your data, generally

But it’s not — so we are not guaranteed to, and generally won’t have access to the response instantly — so we supply some code to handle the response, when it comes back later.

$.get('http://someresource.com', function( data ) {
  console.log('are you my data? ', newData) //=> i'm your data!

Whenever the browser (at some unpredictable time in the future) is notified that the request is fulfilled (hurray data!) — it calls back the code that we previously told it to run when the response arrived (at whatever later point that turns out to be).

This non-blocking behavior allows us to manage and provide a significantly improved user experience.