Asynchronous Code — The Ultimate MultiTasker

Imagine if baking could only be accomplished one step at a time: The Parisian boulangère turns the oven on, sits, twiddles her thumbs while the oven pre-heats, then, once the oven reaches the appropriate temperature, she pulls out the butter from the freezer, then again sit, twiddling as she waits for it to thaw, and then, only at the moment it has reached the requisite pliable-but-firm consistency, does she begin assembling the flour and other the dry ingredients that go into her croissant dough. Quelle tragédie! Doubtless, the French would not be so quick to turn up their noses at a loaf of Wonderbread if that were how baking went.

Because JavaScript is a single-threaded language — meaning it has one call stack and can do one thing at a time — it defaults to running code blocs synchronously, line-by-line, top-to-bottom, left-to-right. It’s an approach rather like that grotesquely inefficient baking scene imagined above.

Enter asynchronous programming, which allows code blocs to run in parallel, performing multiple operations at the same time. Dieu merci! And we can be particularly grateful for asynchronous programming when working with code that takes time execute.

The inclusion of callbacks in the code is a tell-tale sign of asynchronous programming. Async callbacks are functions which are called as arguments within other functions. They wait in the background to be called by the outer function to complete an action, a little like a chef de commis awaiting instructions from the chef de cuisine. When called they do the programming equivalent of testing the consistency of the butter to allow the chef de cuisine to focus on the more important elements of the meal.

The function SetTimeOut() is the classic example of a callback. It introduces an inherent delay in the execution of a line of code, thereby allowing time for other code to be executed. By including this function along with a millisecond timeframe, the SetTimeOut function allows the system to go and execute the next line of code during the prescribed millisecond delay before executing the callback.

You’re allowing the program to prepare to do one thing (to say, “Hey, 2 seconds later!”), while letting it go do something else first. Think about how much more efficient that is! While you preheat the oven, you can get out the flour. Suddenly, baking croissants doesn’t seem like such a hassle.

Here’s how that efficiency looks when you take it out of the kitchen and put it in a program:

console.log(‘Hey, right now!”)=> Hey, right now!
=> Hey, 2 seconds later!

Promises are another way that JavaScript manages asynchronous actions. Instead of using callbacks to be tapped at a later time, a promise returns an object in real-time as a placeholder. As every Parisian knows, after paying for a croissant, you’re not handed the croissant but rather a receipt — and then experience two minutes of tantalizing delay as the baker pulls the buttery, flakey treat from the display and warms it in the oven before handing it over. That receipt is the promise that, before long, you’ll have a croissant in hand.

This is what a promise looks like in JavaScript:

   // You make a fetch request to the server   //  a promise will be returned   Fetch(“localhost:3000/horses”)   // the first .then will translate this promise object into        another promise, this time in the form of a json object      .then(response => response.json())      // now we can view and manipulate the response object      .then(arrayOfHorses => {           arrayOfHorses.forEach(horse => {           console.log(horse)           })       })}

Fetch is another important function which requires asynchronous code to work effectively. That’s because the process of fetching data takes time — sometimes a longgg time — and it is unpredictable. As a result, Fetch returns a promise representing the eventual completion (or failure) of an asynchronous operation. Promises allow the program to reason with future values before their true value is known. They two examples of .then() in the code snippet above buy time for the server to respond to the fetch request.

The first .then() receives the promise from our fetch and returns a response object. From there, we can call .json on that response object to translate the promise (the response of Fetch) into a .json object. At this point, we have access to the json data — in this case, an array of horses — that we were looking for. The second .then() resolves the returned value, allowing us to view and manipulate that data.

Promise chaining is quite powerful as it allows us to reason with data before we have it as well as integrate a lot of functionality into a singular function. We can fetch data, receive a promise, translate a promise into a json object, iterate over that object to return a singular element of an array.

Asynchronous code, in the many forms it appears, facilitates effective multitasking. It allows for JavaScript, a single-threaded language with one call stack, to act as if it has multiple threads: Code executions can occur parallel to each other — task #2 can be undertaken before task #1 runs to completion.

The croissants are ready when we arrive to buy one in the morning, because the baker doesn’t have to wait for the oven to get to 350 degrees before doing anything. When we hand her our money, we can do so with conviction in the promise that a warm croissant is coming our way. We can only assume, therefore, that there’s asynchronous code at work somewhere within the baked goods economy — and that’s a very good thing.