Want To Build Win8/WinJS Apps? You Need To Understand Promises.
If you’re not following me on Twitter, you may not know about my current project work. I’m working with Christopher Bennage and the Microsoft Patterns & Practices group to build a Windows 8, WinJS, Metro-style app with HTML, CSS and JavaScript. It’s a tremendously fun project, and I’m learning a lot – not only about Windows 8 and metro style apps, but also about raw ECMAScript-5 based development, with no shims or facades, no jQuery and no Backbone.js. And one of the most important things that I’ve learned about WinJS development so far, is that if you want to build apps for Windows 8 with HTML and JavaScript, you must have a solid understanding of asynchronous JavaScript development and promises.
Basic Async JavaScript: Callbacks
The most basic form of asynchronous development in JavaScript is the use of callback methods. If you’ve written a line of jQuery.ajax code or DOM event handling, you’ve worked with callbacks:
The anonymous functions in both of these example are callback functions. They are functions that are called at some non-deterministic point in the future. They may be called immediately. They may be called a few seconds from now. They may never be called. The circumstances in which these anonymous callback functions are executed is up to the code that we are calling initially. Fortunately, these circumstances are documented within the jQuery API and documentation and we can be reasonably certain about the timing of the execution of these callbacks.
The reason that callbacks facilitate asynchronous JavaScript is due to the non-deterministic nature of calling them. As the designer of the API that takes in a callback, you are handed a direct reference to a function when a callback is passed in to your methods parameters. This allows you to call that function whenever you need to:
In the case of asynchronous code, such as animations, DOM click events, and AJAX calls across the network, the callback that is supplied to the method is not fired immediately. It is fired when a response from the external network call returns, when the DOM element is manipulated by the user, or when the animation completes. The function that is doing the work simply holds on to the callback reference and calls it when necessary.
The Problem With Callbacks
Callbacks are a very useful and tremendously powerful tool. They also have some oddities and quirks related to the “this” variable (JavaScript’s context), but that can easily be managed. But worse than managing “this”, callbacks have a much deeper problem relating to code readability and maintainability.
Look at what happens to the code when we have multiple nested callbacks:
Yes this is a contrived example, but it is based on the realities of raw callback-based async code in JavaScript. I’ve seen code 10x worse than this in any number of JavaScript applications. Heavy use of jQuery tends to make this especially awful as we add more and more code to handle more and more sub-sequent callbacks based on changing state within our application.
Fortunately, it doesn’t have to be this way. There are some simple things we can do to help clean up the nested callback nightmare, including the use of delegated events within view objects (how Backbone handles DOM events in views), named methods and method pointers instead of anonymous callback methods (as described by Rob Conery in his post on cleaning up callbacks with Node – equally applicable to browser based code and WinJS code), promises (which I’ll get to in a moment) and some other interesting implementation such as using “reduce” function calls with promises, etc.
I Promise To Call It, But I Really Don’t Care About Your Callback
Promises are a powerful tool that provides some rather significant benefit to both the function that previously took a callback as a parameter, and to the code that needs to provide a callback to the method being called. In short, a promise decouples the callback from the function call, while providing a more flexible method of executing callbacks for code that is potentially asynchronous.
Ok, what that really means is that a function that previously took a callback method no longer needs to take that callback method. Instead, it can return a promise object. The promise object itself can then handle registering and calling as many callback methods as needed. When the code in the called function is done, it resolves or completes the promise (depending on which promise implementation you’re using – more on that in a bit). Resolving or completing the promise will cause all of the callbacks that are registered with the promise to be executed.
This function used to take a callback, as shown in previous examples. But now it returns a promise instead. To make use of this, we can call it like this:
Note that we are still using a callback function, but we’re no longer passing the callback in to the function that we’re executing. Instead, we’re passing it to the promise’ “then” function. This is the function, in Promises/A syntax and in (jQuery’s $.when/then syntax), that gets called when the promise is completed or resolved successfully. This means that when the function we called completes and has all of the information that it needs, it called “promise.complete()” which caused all of the registered “then” callbacks to be executed.
One of the primary benefits that promises provides to the code that returns the promise, is the decoupling of the function being called and the callbacks being executed. In the earlier examples, the function being called had to explicitly know about the callback method. It should ideally check for the existence of the callback – to make sure it’s not undefined or null – and also check to make sure it’s a function. This is a lot of noise just to call the callback, but it’s necessary noise. A promise reduces this noise significantly. If a function is creating a promise object, it doesn’t need to care about the callbacks that are going to be called. It only needs to care about calling the “complete” method (or “resolve” method on jQuery promises). Beyond this, the function returning the promise doesn’t care about your callbacks. It doesn’t need to check for valid functions, check to make sure the callback exists, or do anything else to make sure it can call the callback. It just calls “complete” and the promise worries about that other noise.
There are a number of other benefits that promises bring to the table, too: including more flexibility, the ability to manage multiple callbacks, a guarantee that your registered callback will be fired (even if it’s added after the promise is resolved), and more. While these are important topics to understand – especially the part about handling error conditions – I’m going to leave those other benefits as explanations for other material that I’ll link to at the bottom of this post.
Too Many Promises
Promises aren’t anything new in JavaScript and certainly not in Software development. They’ve been around for a while now. Unfortunately for JavaScript, though, they aren’t a set-in-stone standard (like all the good patterns in JS, it seems) and there are a number of competing specs for promises. If you look at the CommonJS wiki for example, you’ll find no less than 5 specifications for promises (including one redacted). jQuery has it’s own flavor of promises that it uses (and which I’ve talked about before). And there are other JavaScript libraries that implement various flavors of promises on their own, at least partially if not creating a complete promise implementation.
This is rather unfortunate as it just creates a lot of confusion. There is one spec that seems to be gaining more momentum and popularity among them, though: the CommonJS Promises/A spec. The unfortunate side of this, though, is that jQuery’s promises are very different than the Promises/A spec in terms of the API and semantics of the method names. Functionally they are very much the same, but they are facilitated in ways that are just slightly different – and different enough to cause some frustration. It would be nice to see jQuery move to the Promises/A spec, but that seems unlikely at this point.
WinJS Promises: Promises/A
Hey, remember when I started this blog post and was talking about WinJS and building apps for Windows 8? … right 🙂
One of the first thing you’ll notice when getting in to WinJS development and really using the framework to build your applications, is the prevalent use of promises. And they are EVERYWHERE. The first file you open when you create a new project (other than a “blank” project) has this line of code in it, in fact:
What’s even more fun about that, though, is that this is nested inside of a callback function for an event handler. So… yeah. How’s that for some async JS love in WinJS? 🙂
As you get further into working with WinJS and the WinRT runtime APIs (found in the “Windows” namespace), promises will become more and more common. Any time you want to access the file system to load images or other files, you’re going to be writing async JavaScript. Any time you want to make a connection to a web service to get some data, it’s async again. Anytime you want to do just about anything that isn’t done directly in the application’s memory space with your code, it’s going to be async. And nearly every time you do anything async with JavaScript in a WinJS app, it’s going to be done with promises. This even bubbles it’s way up to your own code after a while. It’s not something you can get away from.
For example, in the app that I’m helping to build for the P&P team, for example, we’re working on creating a “Live Tile” for the application. This involved a countless number of asynchronous calls out to the file system, to various streams of information, and to get and set the template used to create the tile for the app. We did everything we could to hide the implementation details behind some appropriate abstractions, and the code turned out clean. But it required a heavy use of promises in the calls we were making, as well as the code we wrote for our API.
Of course we could have used callbacks. It would have worked:
But I personally prefer the promises version:
It’s much more simple, much more clean, and much easier for me to read and understand.
Not A Golden Hammer Of Smashing Problems
While promises are certainly useful in cleaning up async code, and it is necessary that you understand them to work with WinJS effectively, it’s not a complete solution and you can still do stupid stuff with them. Take a look at this code, for example (part of the spike to learn how to build Live Tiles, creating a thumbnail from an existing image file):
This is a giant mess… but it uses promises! The problem here is that the promises are being abused as a fancy inline, nested callback mechanism. We may as well be using standard callbacks instead of promises at this point. Promises certainly can be used to clean up code, but promises themselves are not an end-all shiny hammer of awesomeness.
(And don’t worry about this sample too much. We’ve already cleaned this up for the real / production version of the app – this was just a spike to learn).
There are still other patterns and practices that you need to understand, such as JavaScript modules, namespaces, object-oriented development, functional aspects of JavaScript, and much much more. Hopefully this little taste of promises will get you ready for what you need to know and provide some context for further ready and study. You need to understand promises anyways, and if you’re going to work with WinJS and WinRT apps in Windows 8, there is no chance of doing so successfully without knowing promises in and out.
Further Reading
There’s a lot more to asynchronous JavaScript than can be fit in to this blog post. Here are some of the articles and book I recommend reading, to get yourself up to speed on what you’ll need to know for working with async JavaScript in general, nearly all of which will be applicable to WinJS apps:
- Trevor Burnham’s “Async JavaScript” e-book. This is easily my highest recommendation. You need to buy this book right now. The first two or three chapters are worth the cost of the entire book, alone. The rest of the book is a great discussion on async techniques and tools in JavaScript.
- CommonJS Promises wiki – hardcore, down and dirty specs for promises
- The Qjs documentation – lots of very interesting ideas for composing promises in JavaScript
- Async Programming in JavaScript with Promises – by Matt Podwysocki
- jQuery promise
- WinJS Promise object
- Asynchronous programming in Metro style apps
- Asynchronous programming in JavaScript / Metro apps
- WinJS Promises Sample App
I’m sure there are a thousand more articles, blog posts, videos and books on this. Feel free to drop some links in the comments with your favorite async-js / promises material.
Want To Truly Understand Promises?
If you’re still trying to wrap your head around promises, trying to understand how they actually work and what they really do, you’re not alone. Promises are relatively new, and relatively misunderstood in the world of JavaScript programming. But I’ve got something that can help. I’ve produced a screencast that shows you how promises really work, behind the scenes, by walking you through the process of building a very basic promise library, from the ground up.
If you’re looking to wrap your head around these powerful objects, check out WatchMeCode Episode 13: Promises From The Ground Up.