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. (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)

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.

I plan to follow up soon with posts about the two main patterns to manage asynchrony — callbacks and promises.

Resources:

Leave a Reply

Your email address will not be published. Required fields are marked *