651.288.7000 info@intertech.com

What Is A Promise?

When handling asynchronous operations in JavaScript, such as AJAX requests, or disk IO in Node, the traditional way was to provide callback functions to these to be executed when they complete.  Promises reverse this approach.  When executing asynchronous operations, many functions now return a promise that “resolves” when the operation completes.  We then, optionally, attach a callback function to that.

This may sound confusing or maybe not very useful, so let’s look at an example.  Let’s say we wanted to check if a specific file existed, and delete it if it did.  Then, you wanted to create a new file with new content in its place.  The following code snippet illustrates how to do this without using Promises.   

Note: All some of my examples use TypeScript, but are 100% applicable to JavaScript.

Notice how messy it gets as the number of callbacks accumulate. Of particular note, we are forced to make two paths of execution that include the writeFile method. Since unlink is asynchronous, we can’t just execute the writeFile method after unlink, because unlink may not be done deleting the file yet.

Now, let’s look at how we’d do this with Promises.  Notice that, because we return a promise, we don’t need a callback function passed into ours.  The caller of our function will handle that as they need.

This is a little easier. Notice that we only have the writeFile call in one code path. We also don’t have to remember to execute a callback. Of course, we do have to remember to return our promises at the end of each call.

Try-Catch Implications

Promises have a special ‘catch’ method, that can be chained with the ‘then’ method (or not). It’s important to understand that wrapping a promise in a try-catch block will not typically catch errors occurring in your Promise. By the time the Promise’s code is executing, it’s typically not inside the try-catch block anymore.

The following code shows the proper way to catch errors using our previous example.

Async & Await

You may have seen the ‘async’ and ‘await’ keywords in .NET and think they’d be the same here.  I know I did.  While they are similar, they’re not the same.

Anything that returns a promise can use the ‘await’ keyword to indicate that everything after that line must wait for the result of the promise.  The net effect is that all code after a line with ‘await’ in it would be wrapped in the ‘then’ method of the promise.  Further, when assigning the result to a variable, it is automatically unwrapped from its promise.  This allows you to write your asynchronous code the same way you would synchronous code.  Just remember that this is syntactical sugar, and the JavaScript engine is doing the dirty work for you.

Another cool feature about ‘async/await’ is that you can place your code in try-catch blocks like you would with asynchronous code, and it will work as you expect!

Functions that use the ‘await’ keyword in its body must be marked ‘async’ in its declaration, and must return a Promise.  Further, ‘await’ may only be used in a function, so you can’t use it at the file level.

Here is our Promise example using ‘async’ and ‘await’.

Creating Promises

A lot of times, the term ‘asynchronous’ is mistakenly thought of as something run on another thread – even if we don’t control that thread. When we think of asynchronous code though, it may not be of some mysterious origin. We handle asynchronous events all the time when a user presses a button on our page or interacts with a control. Just like any other asynchronous scenario, we can create a promise to respond to a button press too.

The following example illustrates how to wrap a button click in a Promise.  I should point out again that Promises resolve once and only once, so using them for event handlers are less practical.  However, say you have a popup control that’s always created on the fly, then it would make sense to provide a Promise that resolves when it’s closed.

Here, we have a dialog that sits over our main content.  When the user presses the “Close” button, it will hide the dialog. 

The Promise constructor takes a function parameter that takes a ‘resolve’ and ‘reject’ function as arguments.  When the conditions of the promise are met, call the resolve method.  The ‘resolve’ method can be called with or with out a parameter, which will be returned by the promise.  Not illustrated in this example is that the ‘reject’ method is how you throw an error.  It also takes a parameter, which should contain your error details.  If you’re not sure what those are, it would be the same thing you’d use in your throw statement, which is commonly a string describing the error, but it could be anything.

JavaScript is Not Multi-Threaded!

Finally, I need to point out a misconception I had when I first learned about promises.  Anything can be wrapped in a Promise using the technique I described above.  Wrapping something in a Promise does not mean it runs on another thread though.  JavaScript itself is not a multi-threaded language.  There are some features of the browser and in Node that allow you to perform tasks on other threads, but placing code in a promise does not make it run in a separate thread – or even asynchronously.  They will simply resolve inline if there are no asynchronous calls performed within it.

About Intertech

Founded in 1991, Intertech delivers technology training and software development consulting to Fortune 500, Government and Leading Technology institutions. Learn more about us. Whether you are a developer interested in working for a company that invests in its employees or a company looking to partner with a team of technology leaders who provide solutions, mentor staff and add true business value, we’d like to meet you.