0% found this document useful (0 votes)
12 views

Demystifying Promises in JavaScript: How Do They Work? - by Michael E Colley - Nov, 2021 - Better Programming

The document discusses promises in JavaScript, explaining how JavaScript handles synchronous and asynchronous code, what promises are, how they work and their benefits. Promises allow asynchronous tasks to run sequentially, passing returned values between callbacks, and help with error handling.

Uploaded by

Dani Blanco
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
12 views

Demystifying Promises in JavaScript: How Do They Work? - by Michael E Colley - Nov, 2021 - Better Programming

The document discusses promises in JavaScript, explaining how JavaScript handles synchronous and asynchronous code, what promises are, how they work and their benefits. Promises allow asynchronous tasks to run sequentially, passing returned values between callbacks, and help with error handling.

Uploaded by

Dani Blanco
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 6

Demystifying Promises in

JavaScript: How Do They Work?


Learn about promises to make sense of what they
are and how you can use them in JavaScript
Michael E Colley

If you head over to the ECMAScript 6 documentation, you’ll see that under
Promises lies one sentence. “First class representation of a value that may
be made asynchronously and be available in the future.” Are you
wondering what that means?

Yeah, me too. It’s probably this, among many other misunderstandings


about how JavaScript executes code under the hood, that has contributed
to the confusion surrounding the Promise feature in JavaScript.

Well, in this blog post, we’ll aim to demystify exactly how this feature
works so you can implement Promises into your code like a pro. To get to
the Promised land (sorry, not sorry), we first need to understand how
JavaScript handles synchronous and asynchronous code. We’ll then dive
into what Promises are, how they’re helpful, and why you might want to
start using them in your code if you haven’t already.

How JavaScript handles synchronous and


asynchronous code
JavaScript is a single-threaded programming language which means that
it has a single call stack upon which it can push new function execution
contexts. In other words, it can do one thing at a time.

Not only that, but it does it with zero regards for whether the previous
code has finished executing further up your .js file, making it synchronous.
“Ok,” you exclaim, “but if that’s true, how can I both click buttons that do
stuff on a browser while I’m waiting for other code to load? How can it be
that I can do many actions, some of which appear to have blocking
functionality simultaneously while other code runs?”. Great questions,
thanks for asking.

Well, in short, it’s the browser or any other higher-level runtime that runs
JavaScript allowing you to do these things. These higher-level
abstractions give us other data structures similar to the call stack,
allowing us to store code to be run later or at different times.

Under the hood, the browser uses these abstractions to manage what
gets put onto our call stack. Two examples of these other data structures
being used in conjunction with our call stack are setTimeout() that
applies an input time constraint to when a callback is executed or a Fetch
request that waits for the receipt of a response from a server before
processing the following line of code.

Both are incompatible with JavaScript’s basic single threadedness, but the
abstractions give us additional powers that allow for what appears to be
non-single threaded behavior. In Chromium, these tools are known as
WebAPIs and in Node C++ APIs. They juggle the code asynchronously —
ensuring it doesn’t interrupt code executed in the main thread of
execution. You might be thinking at this stage, “alright, then that means
that this is executed in another thread”.

But that depends on the engine executing your JavaScript. In the case of
Chromium, this is simply the illusion of what appears like multithreaded
concurrently executed code. We won’t go into any more detail on this
since it warrants its own set of posts by itself, but this should give us
enough context to have an understanding of what these higher leveled
abstractions are capable of in JavaScript!

Ok, so now we’ve got our understanding down for asynchronicity, let’s
now move back onto the star of the show, Promises.

What’s even a Promise?


A Promise is a type of JavaScript object representing a “Promised” future
outcome. That’s it. While this isn’t a very clear description — especially if
you’re just piecing together your mental model of Promises, let’s focus on
the JavaScript object part of that definition I just shared. At the most basic
level, it’s a series (or chain) of objects within which there are callbacks.
Chain because they are connected and if one link breaks the entire
Promise does. Practically speaking, it allows you to do a few things, let’s
take a look at those:

First, you can set up code that relies upon executing and completing other
callbacks in a stepped or blocked manner.

This is very powerful since it gives you the capability to closely control the
flow of execution, which is terrific when you want to interact with a server,
execute code upon the successful receipt of data, or create throttle
functionality to avoid your server being pwned.

Examples of this in action might include rendering your feed items on


Instagram after the page loads or having Netflix play a video once
sufficient data has been downloaded into your client.

Setting up asynchronous tasks to run-one-after-the-other-is-completed


is known as Promise chaining, typically put in practice using the .then
syntax. Yes, there’s the specific syntax to learn here, but believe me, this
is a small price to pay when the alternative is nesting callback and visiting
callback hell.

Promise chaining also allows you to pass the returned values down
between the callbacks in a Promise chain. In the example of the Fetch
request, it means sending a request to your server, waiting for a response,
and then processing that response when it comes back to our client.

See the code block below to understand Promise syntax and how
Promises operate. I’ve tried to use very verbose function names to give
you a sense of what’s going on:

new Promise(function doThisFirst(resolve, reject) {


console.log('Hey, I just met you')
resolve()})
.then(function doThisSecond() {
console.log('and this is crazy')
}).then(function doThisThird() {
console.log('But here\'s my number')
}).then(function doThisFourth() {
console.log('so call me, maybe')
}).catch(() => {
console.error('Number engaged');
});

Second and in addition to my first point, because we can run what


appears to the user as blocking tasks whilst still running our main thread
of execution, we get the flexibility to execute other code. This means that
the user experience is preserved as they can go about other tasks in the
browser without being held up by the Promise logic.
In Chromium, this is achieved by the browser doing a tonne of juggling
using the Event Loop to run our code in a concurrent-like way. To
understand this in more detail, check out the great talk that Phillip Roberts
did at JSConf in 2014, which explains how that works.

Third, Promises give you the ability to tie in error handling logic neatly.
This is because of how Promises are executed. A Promise object chains
functionality together to either be pending, resolved (fulfilled), or rejected.
With the addition of the .catch Promise syntax, you can have your
Promise execute a console.log of your error upon the failure of one of the
functions called within the Promise chain. Conceptually similar JavaScript
concepts are try-catch blocks. In the code block above we’d log “Number
engaged” if for whatever reason the other chains in the Promise failed.
Promise error handling helps with debugging since the error is contained
in the block of works associated with the Promise workflow. This is
particularly useful when you make network requests and troubleshoot why
you weren’t served data from a given API endpoint.
Promise state flow

As a heads up, there is one main limitation you might come across when
playing around with Promises. As I said at the start, they are JavaScript
objects but special ones so you can’t simply manipulate them as you
would an array or regular object literal. If you console.log() out your
Promises you’ll probably see what I mean. What is returned is illegible and
unusable. Something like this:

Promise { <pending> }

Instead when working with Promises be sure to have the callback leverage
closure to take whatever data is manipulated inside your Promise and
update a relevant data type in the lexical scope of the parent execution
context, thereby assuring that you can both get the most out of your
Promises but not run into any usability bugs when coding.

Hopefully, by now, you will understand more about how JavaScript works
under the hood than what you did at the start of the article and, in turn,
how Promises can help you when you code. Of course, there’s much more
to be said on the topic of Promises, but as a point of departure, we now
know that they can give us the flexibility to write blocking asynchronous
and graceful error handling code.

You might also like