#6 Understanding Promises

Relax, I’m not going to wax philosophical about how no one can keep a promise these days (although now that you mention it...). I'm talking about the promise programming design pattern in Javascript.

In modern programming there are two major concepts that every programmer needs to understand when thinking about how CPU’s compute their code: asynchronous(“Async”) vs synchronous (“Sync”).

Synchronous processes can be thought of as doing things in a strict and explicit order: Something1, then Something2, then Something3, etc.

Asynchronous can be thought of as doing Something1 and not waiting for Something1 to finish before you tackle Something2.

The problem with Sync only code is that it can be unnecessarily slow and cause the CPU to wait when it could be using cycles to do other things. Whereas the problem with Async code is that sometimes you need the results from Something1 before you tackle Something2 (i.e. you need to control the flow of results).

You can think of writing code as giving someone very explicit cooking instructions. Take for example making some eggs and toast:

Step 1: Get two eggs from fridge
Step 2: Take out pan, place on stove top, turn on stove to medium
Step 3: Take eggs from Step 1, crack them in the pan from Step 2.
Step 4: Cook eggs for 3 min, turn off the stove
Step 5: Get two slices of bread from the pantry
Step 6: Take out slice of bread and place in toaster, toast
Step 7: Get a plate out of the cupboard
Step 8: Put toast on plate and eggs on plate

Eggs and toast in 8 steps, not bad. That said, from a compute time perspective, we were a bit inefficient. Note that on Step 4 we waited for 3 minutes (!) and did nothing during that time besides watch the eggs cook. You would never do that!

Introducing the Promise:

When we write this program using promises it’s a bit different:

function makeEggs(rawEggs){

let cookingPromise = new Promise( (resolve, reject ) =>
{
let cookedEggs;
// When eggs are done, send it out for consumption:
resolve( cookedEggs )
} return cookingPromise;}function makeToast(untoastedBread){ let cookingPromise = new Promise ( (resolve, reject) =>
{
// When toast is done, send it out for plating: resolve( toastedBread ) } return cookingPromise;}

Now we have two functions that: (1) makeEggs; and (2) makeToast, both of which return cooking promises. The way to think about this is like you sent those two tasks to separate cooks who PROMISED (see what I did there?) to cook you the food and will let you know once they’ve RESOLVED (this one was less clever) their task. Once they are done, they will have “resolved” the promise, thereby producing the results of the process that you desired. (Note: from a performance perspective, the correct way of thinking about it is, while one cook waits for the eggs to cook, the same cook runs and goes to toast the bread, constantly looking back at the eggs to see when they are done. For now, however, the two cooks analogy helps people visualize it better.)

With the result of a promise out of the way, here’s where the magic happens:

// The makeEggs and makeToast functions were defined above
let eggsPromise = makeEggs(newEggs);
let toastPromise = makeToast(newSliceOfBread);
Promises.all( [eggsPromise, toastPromise] )
// Once the promises have resolved, do the following:
.then( resultsOfCooking => {
// Plate the eggs and toast
plateIngredients( resultsOfCooking )
})

What promises let us do is process both the eggs and toast separately, and then when both processes have completed you have the benefit of receiving the results at the same time. As a result, you don’t have to write your code in a way that says: Step 1, then Step 2, then Step 3.

I want to make something clear, this is not to be confused with multi-threading a process (which we will tackle in another post). The promise-based design pattern allows you to run commands asynchronously, but does not provide the performance benefits of multi-threading. Typically these types of patterns are used when the timing of results from a function is dependent on some other event. For example, when Server_A is making a call to Server_B and does not know when it will receive a reply. Instead of hanging there and wasting compute cycles, it continues to process commands on the same thread.

But Tony, what about async / await keywords?

Technically you can write something like this:

async function makeBreakfast(rawEggs, untoastedBread) {    let cookedEggs = await makeEggs(rawEggs);    let toastedBread = await makeEggs(rawEggs);    plateIngredients ( cookedEggs, toastedBread )}

I think of the await keyword as trapping the processing until that line resolves. This prevents a racing situation where we use the results of a function before we know whether it has produced a result. Just because you can, doesn’t mean you should, which is why I avoid async / await keywords unless absolutely necessary. The problem I find is that it disrupts the flow of the code and you start to get into a maze of “crap, what else do I have to prefix as async.” At the end of the day, it’s just syntactic sugar for dealing with promises to make it feel and read more like Sync code. If it’s Sync, then write it in a Sync way. If it’s Async, then write it in an Async way. More junior coders (including myself back in the day) pepper the keywords all over the place as a result. The pattern that I find easiest for folks to understand (and therefore maintain) is properly using the .then and .catch methods. We’ll tackle those methods and concepts around chaining and error handling in a future post.

--

--

--

CEO / Chief Engineer of HyperDraft, Inc.

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

How to use Zustand which is react state management library

How Deno Deploy Changes the Game for JS Server Hosting

TypeScript — A JavaScript Compiler

I Started a Fight with APIs and Lost Miserably

Pick by Values in TypeScript— A Widely Used Trick in Many Famous Projects That You Should Know

How Raygun increased throughput by 2,000% with .NET Core (over Node.js)

How do Functions and Variable Environment Work Together in JavaScript?👀

Storyline and 360 photo?

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Tony Thai

Tony Thai

CEO / Chief Engineer of HyperDraft, Inc.

More from Medium

The State of useState

Phase-2 “REACT.JS”

3 UNCOMMON MISTAKES WE MAKE AS BEGINNERS WHILE LEARNING HOW TO CODE

Changing my Views: Controlled Forms

change