Asynchronicity: An Intro to Asynchrony in JavaScript

Anna Reed
The Startup
Published in
4 min readSep 19, 2020

--

image source: ABC New York

Here’s a scenario: imagine you’re the CEO of a wildly successful new company. You have a luxury office at the very top of a high-rise in your city of choice. You are absolutely drowning in money and fame. Unfortunately, you are also drowning in work. Now, you have three things to do before you attend a meeting with your employees in an hour. First, you need to create a spreadsheet for the company’s budget. Second, you need to have your assistant pick up any company mail from the mailbox downstairs. Third, you need to email your new budget to the company’s investors.

So you get to work in Excel, and after forty minutes you’ve got your monthly budget planned out. You call your assistant, and tell them to go down to the first floor and get your mail. And then you wait… and wait… and wait. Twenty minutes later, your assistant comes back, dripping with sweat. The elevators are out of order, and they’ve just had to jog down and up ten flights of stairs. You now have to rush to your meeting, and your stockholders won’t receive the budget until afterwards!

Except, that’s not what a hard-working entrepreneur would have done, is it? Sitting there twiddling your thumbs while your assistant did your errands would be an enormous waste of time. While they were braving the staircase, you could just as easily have emailed out your budget, and had time to spare!

Congratulations, snazzy new business exec! You’ve just uncovered a concept called asynchrony.

Sorry; no relation to the Police album

To start to tie this back into JavaScript, let’s try illustrating the previous list of tasks in pseudo-code.

const investors = ["Warren Buffet", "Bill Gates", "Tony Stark", "another famous rich person"]createBudget();
haveAssistantGetMail();
investors.forEach(investor => {
emailBudgetTo(investor);
}

In this example, haveAssistantGetMail() is an asynchronous function. In other words, it’s a function that JavaScript knows may take awhile, so while it’s running, JavaScript will go ahead and move on to the next line of code. The code in this block will actually be executed in the following order: first, createBudget() is run. Next, JavaScript starts running haveAssistantGetMail(). While this is happening, the next code block involving emailBudgetTo() is going to be executed. Officially, haveAssistantGetMail() isn’t finished running until after that code is run. So, in terms of our metaphor, our assistant isn’t going to come back into our office until after we’ve emailed the budget to everyone. Examples of actual asynchronous functions in JavaScript include fetch() and setTimeout().

The pluses of using asynchrony are clear: it’s efficient, it saves time, and it allows us to execute more complex code without worrying too much about load times. But, like any effective tool, there is some danger in using it incorrectly.

In our business-related extended metaphor, there’s no real relation between haveAssistantGetMail() and the emailBudgetTo() code block, except that they are both part of our code. Our ability to email our budget is not affected by the presence of our assistant in our office, nor is it affected by whether or not we have gotten our mail for the day. But what if it was? What if one of the pieces of mail we were expecting was, in fact, the list of our investors? In that case, we couldn’t email out our budget until after we got our mail.

const investors = [];createBudget();
haveAssistantGetMail();
investors.forEach(investor => {
emailBudgetTo(investor);
}
function haveAssistantGetMail() {
getListOfInvestors();
}

Because we already know that haveAssistantGetMail() is asynchronous, and won’t finish running until after the rest of our code has, we can extrapolate that emailBudgetTo() will be firing… exactly zero times, since it will still be responding to an empty array of investors. This block of (pseudo-)code will not result in all of our tasks being done!

There are a couple of ways to work around this so that our code works as intended. One of the most up-to-date is to use .then():

const investors = [];createBudget();
haveAssistantGetMail()
.then(){
investors.forEach(investor => {
emailBudgetTo(investor);
}
};
function haveAssistantGetMail() {
getListOfInvestors();
}

.then() ensures that the code block within will not execute until after the asynchronous function it follows is finished. In this case, the code is essentially acting as if it were not asynchronous at all: the emailBudgetTo() code block will not fire until after haveAssistantGetMail() finishes running. This format allows us to wait to send out emails at until after our list of investors has arrived. Of course, in doing so, we’ve ensured once again that our work is going to take longer than an hour… fortunately, in actual Javascript, most code is going to fire in milliseconds!

To learn more about asynchrony:

Asynchronous JavaScript in Mozilla’s JS Documentation

Asynchronous Programming in Eloquent JavaScript

Asynchrony and Promises on JavaScript.info

--

--