Asynchronous programming gave me five seconds of my life back...here's how you can get five seconds back too.

Anyone of a certain age remembers the many times that technology put us through tests of enduring patience, particularly in the early, dial-up internet days of the late nineties. These tests of patience–waiting for the mechanical tone-based handshake between your device and the internet service provider–were an early testament to how essential the internet is for all of our lives. Nothing else could create a positive pavlovian response to such a grating atonal noise. Though the internet is obviously now a standard fixture for our everyday lives, our need for a stronger, faster, more efficient and robust system has pushed this technology exactly towards that. Among these advances, asynchronous functions in code have aided in faster loading and a more efficient, sensible way of ordering execution flow within the code.

With synchronous code, Javascript reads and executes each line of code from top to bottom. Each line of code must finish processing before moving on to the next one, as each successive line of code may refer back to previously declared variables, for instance. For shorter code working with smaller datasets, this synchronous process appears nearly instantaneous. Consider the following example of a random wacky name generator:

Although there are functions called within functions, this code is still running synchronously. The generateString function within generateClassroom must be completed before we can push its result to the array, which eventually gives us a string of the wacky students in our classroom.

Running the generateClassroom function with 3, 4, 5, or even 100 or 1,000 students as its argument yields fairly instantaneous results. We start to get into trouble when passing in larger arguments, however. The code takes some time to load with 1,000,000 students, and those of us who lived through the nineties quickly forget our dial-up patience. While making a classroom of 1,000,000 students is somewhat of a farfetched example, it is not uncommon to be working with datasets of that size and much greater.

Asynchronous functions allow us to access, display, and render huge datasets, while the other HTML and simultaneous functions of the overall code can run. This buys time for our impatient 2023 brains, as we can still interact with a dynamic, engaging site without losing up to five precious seconds of our lives. Asynchronous functions operate by first returning to us a Promise object–a receipt that the server has heard us and is working on responding. We can illustrate fetch() requests as an exemplar piece of asynchronous code.

Fetch() is a global method that takes one argument, which is the URL where the datasets are located. Fetch() returns a Promise object representing the server’s response, upon whose results further code can be enacted. Promise objects exist in one of three states: pending, fulfilled, and rejected. Pending represents the initial state of the object, where the request has not yet been fulfilled or rejected; fulfilled promises mean that our request was received, and a response was successfully sent; and rejected promises mean that our operation has failed for any number of reasons. We can view both the overall Promise object, as well as console log the representation of its response:

Once the status of the Promise has been resolved, we can chain a then() method onto our result and process the success or failure of our fetch() promise.

then() methods take a callback function as an argument. Within a simple GET request, our first chained then() method will take the promise’s representation of the server response and oftentimes parse that representation into a JSON format within its callback function. Interestingly, this first then() also returns a Promise object–one that is resolved depending on if the representation was successfully formatted into a JSON object or not. After this second promise, we can finally chain on a second then() to render our JSON object to the DOM, console log our data, or run these data through any other function we wish.

As these asynchronous functions are churning away, the rest of our synchronous code can shine. These two processes used in tandem open up advantages and efficiencies that our 1995 brains wouldn’t even be able to comprehend.

Credits:
https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Introducing

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises

https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch 

https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise