Demystifying Promises - Programming Windows Store Apps with HTML CSS and JavaSript (2014)

Programming Windows Store Apps with HTML CSS and JavaSript(2014)

Appendix A
Demystifying Promises

In Chapter 3, “App Anatomy and Performance Fundamentals,” we looked at promises that an app typically encounters in the course of working with WinJS and the WinRT APIs. This included working with the then/done methods (and their differences), joining parallel promises, chaining and nesting sequential promises, error handling, and few other features of WinJS promises like the various timeout methods.

Because promises pop up as often as dandelions in a lawn (without being a noxious weed, of course!), it helps to study them more deeply. Otherwise, they and certain code patterns that use them can seem quite mysterious. In this Appendix, we’ll first look at the whole backstory, if you will, about what promises are and what they really accomplish, going so far as to implement some promise classes from scratch. We’ll then look at WinJS promises specifically and some of the features we didn’t see in Chapter 3, such as creating a new instance of WinJS.Promise to encapsulate an async operation of your own. Together, all of this should give you enough knowledge to understand some interesting promises code, as we’ll see at the end of this appendix. This will also enable you to understand item-rendering optimizations with the ListView control, as explained in Chapter 7, “Collection Controls.”

Demonstrations of what we’ll cover here can be found in the WinJS Promise sample of the Windows SDK, which we won’t draw from directly, along with the Promises example in the appendices’ companion content, which we’ll use as our source for code snippets. If you want the fuller backstory on async APIs, read Keeping apps fast and fluid with asynchrony in the Windows Runtime on the Windows developer blog. You can also find a combined and condensed version of this material and that from Chapter 3 in my post All about promises (for Windows Store apps written in JavaScript) on that same blog.

Finally, as a bonus, this appendix also deconstructs the batching function used to optimize ListView item rendering, as described in Chapter 7 in the section “Template Functions (Part 2).” It’s a bit of promise-heavy code, but it’s fascinating to take it apart.

What Is a Promise, Exactly? The Promise Relationships

As noted in the “Using Promises” section of Chapter 3, a promise is just a code construct or a calling convention with no inherent relationship to async operations. Always keep that in mind, because it’s easy to think that promises in and of themselves create async behavior. They do not: that’s still something you have to do yourself, as we’ll see. In other words, as a code construct, a promise is just a combination of functions, statements, and variables that define a specific way to accomplish a task. A for loop, for instance, is a programming construct whose purpose is to iterate over a collection. It’s a way of saying, “For each item in this collection, perform these actions” (hence the creation of forEach!). You use such a construct anytime you need to accomplish this particular purpose, and you know it well because you’ve practiced it so often!

A promise is really nothing different. It’s a particular code structure for a specific purpose: namely, the delivery of some value that might not yet be available. This is why a promise as we see it in code is essentially the same as we find in human relationships: an agreement, in a sense, between the originator of the promise and the consumer or recipient.

In this relationship between originator and consumer there are actually two distinct stages. I call these creation and fulfillment, which are illustrated in Figure A-1.

images

FIGURE A-1 The core relationship encapsulated in a promise.

Having two stages of the relationship is what bring up the asynchronous business. Let’s see how by following the flow of the numbers in Figure A-1:

1. The relationship begins when the consumer asks an originator for something: “Can you give me…?” This is what happens when an app calls some API that provides a promise rather than an immediate value.

2. The originator creates a promise for the goods in question and delivers that promise to the consumer.

3. The consumer acknowledges receipt of the promise, telling the originator how the promise should let the consumer know when the goods are ready. It’s like saying, “OK, just call this number when you’ve got them,” after which the consumer simply goes on with its life (asynchronously) instead of waiting (synchronously).

4. Meanwhile, the originator works to acquire the promised goods. Perhaps it has to manufacture the goods or acquire them from elsewhere; the relationship here assumes that those goods aren’t necessarily sitting around (even though they could be). This is the other place where asynchronous behavior arises, because acquisition can take an indeterminate amount of time.

5. Once the originator has the goods, it brings them to the consumer.

6. The consumer now has what it originally asked for and can consume the goods as desired.

Now, if you’re clever enough, you might have noticed that by eliminating a part of the diagram—the stuff around (3) and the arrow that says “Yes, I promise…”—you are left with a simple synchronous delivery model. Which brings us to this point: receiving a promise gives the consumer a chance to do something with its time (like being responsive to other requests), while it waits for the originator to get its act together and deliver the promised goods.

And that, of course, is also the whole point of asynchronous APIs, which is why we use promises with them. It’s like the difference (to repeat my example from Chapter 3) between waiting in line at a restaurant’s drive-through for a potentially very long time (the synchronous model) and calling out for pizza delivery (the asynchronous model): the latter gives you the freedom to do other things while you’re waiting for the delivery of your munchies.

Of course, there’s a bit more to the relationship that we have to consider. You’ve certainly made promises in your life, and you’ve had promises made to you. Although many of those promises have been fulfilled, the reality is that many promises are broken—it is possible for the pizza delivery person to have an accident on the way to your home! Broken promises are just a fact of life, one that we have to accept, both in our personal lives and in asynchronous programming.

Within the promise relationship, then, this means that originator of a promise first needs a way to say, “Well, I’m sorry, but I can’t make good on this promise.” Likewise, the recipient needs a way to know that this is the case. Secondly, as consumers, we can sometimes be rather impatient about promises made to us. When a shipping company makes a promise to deliver a package by a certain date, we want to be able to look up the tracking number and see where that package is! So, if the originator can track its progress in fulfilling its promise, the consumer also needs a way to receive that information. And third, the consumer can also tell the originator that it no longer needs whatever it asked for earlier. That is, the consumer needs the ability to cancel the order or request.

This complete relationship is illustrated in Figure A-2. Here we’ve added the following:

7. While the originator is attempting to acquire the goods, it can let the consumer know what’s happening with periodic updates. The consumer can also let the originator know that it no longer needs the promise fulfilled (cancellation).

8. If the originator fails to acquire the goods, it has to apologize with the understanding that there’s nothing more it could have done. (“The Internet is down, you know?”)

9. If the promise is broken, the consumer has to deal with it as best it can!

With all this in mind, let’s see in the next section how these relationships manifest in code.

images

FIGURE A-2 The full promise relationship.

The Promise Construct (Core Relationship)

To fulfill the core relationship of a promise between originator and consumer, we need the following:

• A means to create a promise and attach it to whatever results are involved.

• A means to tell the consumer when the goods are available, which means some kind of callback function into the consumer.

The first requirement suggests that the originator defines an object class of some kind that internally wraps whatever process is needed to obtain the result. An instance of such a class would be created by an asynchronous API and returned to the caller.

For the second requirement, we can take two approaches. One way is to have a simple property on the promise object to which the consumer assigns the callback function. The other is to have a method on the promise to which the consumer passes its callback. Of the two, the latter (using a method) gives the originator more flexibility in how it fulfills that promise, because until a consumer assigns a callback—which is also called subscribing to the promise—the originator can hold off on starting the underlying work. You know how it is—there’s work you know you need to do, but you just don’t get around to it until someone actually gives you a deadline! Using a method call thus tells the originator that the consumer is now truly wanting the results.141 Until that time, the promise object can simply wait in stasis.

In the definition of a promise that’s evolved within the JavaScript community known as Common JS/Promises A (the specification that WinJS and WinRT follow), the method for this second requirement is called then. In fact, this is the very definition of a promise: an object that has a property named ‘then’ whose value is a function.

That’s it. In fact, the static WinJS function WinJS.Promise.is, which tests whether a given object is a promise, is implemented as follows:

is: function Promise_is(value) {

return value && typeof value === "object" && typeof value.then === "function";

}

Note In Chapter 3 we also saw a similar function called done that WinJS and WinRT promises use for error handler purposes. This is not part of the Promises A specification, but it’s employed within Windows Store apps.

Within the core relationship, then takes one argument: a consumer-implemented callback function known as the completed handler. (This is also called a fulfilled handler, but I prefer the first term.) Here’s how it fits into the core relationship diagram shown earlier (using the same number labels):

1. The consumer calls some API that returns a promise. The specific API in question typically defines the type of object being asked for. In WinRT, for example, the Geolocator.-getGeolocationAsync method returns a promise whose result is a Geoposition object.

2. The originator creates a promise by instantiating an instance of whatever class it employs for its work. So long as that object has a then method, it can contain whatever other methods and properties it wants. Again, by definition a promise must have a method called then, and this neither requires nor prohibits any other methods and properties.

3. Once the consumer receives the promise and wants to know about fulfillment, it calls then to subscribe to the promise, passing a completed handler as the first argument. The promise must internally retain this function (unless the value is already available—see below). Note again thatthen can be called multiple times, by any number of consumers, and the promise must maintain a list of all those completed handlers.

4. Meanwhile, the originator works to fulfill the promise. For example, the WinRT getGeolocationAsync API will be busy retrieving information from the device’s sensors or using an IP address–based method to approximate the user’s location.

5. When the originator has the result, it has the promise object call all its completed handlers (received through then) with the result.

6. Inside its completed handler, the consumer works with the data however it wants.

As you can see, a promise is again just a programming construct that manages the relationship between consumer and originator. Nothing more. In fact, it’s not necessary that any asynchronous work is involved: a promise can be used with results that are already known. In such cases, the promise just adds the layer of the completed handler, which typically gets called as soon as it’s provided to the promise through then in step 3 rather than in step 5. While this adds overhead for known values, it allows both synchronous and asynchronous results to be treated identically, which is very beneficial with async programming in general.

To make the core promise construct clear and also to illustrate an asynchronous operation, let’s look at a few examples by using a simple promise class of our own as found in the Promises example in the companion content.

Don’t do what I’m about to show you Implementing a fully functional promise class on your own gets rather complex when you start addressing all the details, such as the need for then to return another promise of its own. For this reason, always use the WinJS.Promise class or one from another library that fully implements Promises A and allows you to easily create robust promises for your own asynchronous operations. The examples I’m showing here are strictly for education purposes; they do not implement the full specification.

Example #1: An Empty Promise!

Let’s say we have a function, doSomethingForNothing, whose results are an empty object, { }, delivered through a promise:

//Originator code

function doSomethingForNothing() {

return new EmptyPromise();

}

We’ll get to the EmptyPromise class in a moment. First, assume that EmptyPromise follows the definition and has a thenmethod that accepts a completed handler. Here’s how we would use the API in the consumer:

//Consumer code

var promise = doSomethingForNothing();

promise.then(function (results) {

console.log(JSON.stringify(results));

});

The output of this would be as follows:

{}

App.log in the example Although I’m showing console.log in the code snippets here, the Promises sample uses a function App.log that ties into the WinJS.log mechanism and directs output to the app canvas directly. This is just done so that there’s meaningful output in the running example app.

The consumer code could be shortened to just doSomethingForNothing().then(function (results) { ... }); but we’ll keep the promise explicitly visible for clarity. Also note that we can name the argument passed to the completed handler (results above) whatever we want; it’s just a variable.

Stepping through the consumer code above, we call promise.then, and sometime later the anonymous completed handler is called. How long that “sometime later” is, exactly, depends on the nature of the operation in question.

Let’s say that doSomethingForNothing already knows that it’s going to return an empty object for results. In that case, EmptyPromise can be implemented as follows (and please, no comments about the best way to do object-oriented JavaScript):

//Originator code

var EmptyPromise = function () {

this._value = {};

this.then = function (completedHandler) {

completedHandler(this._value);

}

}

When the originator does a new on this constructor, we get back an object that has a then method that accepts a completed handler. Because this promise already knows its result, its implementation of thenjust turns around and calls the given completed handler. This works no matter how many times thenis called, even if the consumer passes that promise to another consumer.142

Here’s how the code executes, identifying the steps in the core relationship:

images

Again, when a promise already knows its results, it can synchronously pass them to whatever completed handler it received through then. Here a promise is nothing more than an extra layer that delivers results through a callback rather than directly from a function. For pre-existing results, in other words, a promise is pure overhead. You can see this by placing another console.log call after promise.then, and you’ll see that the {} result is logged before promise.then returns.

All this is implemented in scenario 1 of the Promises example.

Example #2: An Empty Async Promise

Using promises with known values seems like a way to waste memory and CPU cycles for the sheer joy of it, but promises become much more interesting when those values are obtained asynchronously.

Let’s change the earlier EmptyPromiseclass to do this. Instead of calling the completed handler right away, we’ll do that after a timeout:

var EmptyPromise = function () {

this._value = { };

this.then = function (completedHandler) {

//Simulate async work with a timeout so that we return before calling completedHandler

setTimeout(completedHandler, 100, this._value);

}

}

With the same consumer code as before and suitable console.log calls, we’ll see that promise.then returns before the completed handler is called. Here’s the output:

promise created

returned from promise.then

{}

Indeed, all the synchronous code that follows promise.then will execute before the completed handler is called. This is because setTimeout has to wait for the app to yield the UI thread, even if that’s much longer than the timeout period itself. So, if I do something synchronously obnoxious in the consumer code like the following, as in scenario 2 of the Promises example:

var promise = doSomethingForNothing();

console.log("promise created");

promise.then(function (results) {

console.log(JSON.stringify(results));

});

console.log("returned from promise.then");

//Block UI thread for a longer period than the timeout

var sum = 0;

for (var i = 0; i < 500000; i++) {

sum += i;

}

console.log("calculated sum = " + sum);

the output will be:

promise created

returned from promise.then

calculated sum = 1249999750000

{}

This tells us that for async operation we don’t have to worry about completed handlers being called before the current function is done executing. At the same time, if we have multiple completed handlers for different async operations, there’s no guarantee about the order in which they’ll complete. This is where you need to either nest or chain the operations, as we saw in Chapter 3. There is also a way to use WinJS.Promise.join to execute parallel promises but have their results delivered sequentially, as we’ll see later.

Note Always keep in mind that while async operations typically spawn additional threads apart from the UI thread, all those results must eventually make their way back to the UI thread. If you have a large number of async operations running in parallel, the callbacks to the completed handlers on the UI thread can cause the app to become somewhat unresponsive. If this is the case, implement strategies to stagger those operations in time (e.g., using setTimeoutor setIntervalto separate them into batches).

Example #3: Retrieving Data from a URI

For a more realistic example, let’s do some asynchronous work with meaningful results from XMLHttpRequest, as demonstrated in scenario 3 of the Promises example:

//Originator code

function doXhrGet(uri) {

returnnew XhrPromise(uri);

}

var XhrPromise = function (uri) {

this.then = function (completedHandler) {

var req = new XMLHttpRequest();

req.onreadystatechange = function () {

if (req.readyState === 4) {

if (req.status >= 200 && req.status < 300) {

completedHandler(req);

}

req.onreadystatechange = function () { };

}

};

req.open("GET", uri, true);

req.responseType = "";

req.send();

}

}

//Consumer code (note that the promise isn't explicit)

doXhrGet("http://kraigbrockschmidt.com/blog/?feed=rss2").then(function (results) {

console.log(results.responseText);

});

console.log("returned from promise.then");

The key feature in this code is that the asynchronous API we’re using within the promise does not itself involve promises, just like our use of setTimeout in the second example. XMLHttpRequest.send does its work asynchronously but reports status through its readystatechange event. So what we’re really doing here is wrapping that API-specific async structure inside the more generalized structure of a promise.

It should be fairly obvious that this XhrPromise as I’ve defined it has some limitations—a real wrapper would be much more flexible for HTTP requests. Another problem is that if then is called more than once, this implementation will kick off additional HTTP requests rather than sharing the results among multiple consumers. So don’t use a class like this—use WinJS.xhr instead, from which I shamelessly plagiarized this code in the first place, or the API in Windows.Web.Http.HttpClient (see Chapter 4, “Web Content and Services”).

Benefits of Promises

Why wrap async operations within promises, as we did in the previous section? Why not just use functions like XMLHttpRequest straight up without all the added complexity? And why would we ever want to wrap known values into a promise that ultimately acts synchronously?

First, by wrapping async operations within promises, the consuming code no longer has to know the specific callback structure for each API. Just in the examples we’ve written so far, methods like setImmediate, setTimeout, and setInterval take a callback function as an argument.XMLHttpRequest raises an event instead, so you have to add a callback separately through its onreadystatechange property or addEventListener. Web workers, similarly, raise a generic message event, and other async APIs can pretty much do what they want. By wrapping every such operation with the promise structure, the consuming code becomes much more consistent.

A second reason is that when all async operations are represented by promises—and thus match async operations in the Windows Runtime API and WinJS—we can start combining and composing them in interesting ways. These scenarios are covered in Chapter 3: chaining dependent operations sequentially, joining promises (WinJS.Promise.join) to create a single promise that’s fulfilled when all the others are fulfilled, or wrapping promises together into a promise that’s fulfilled when the first one is fulfilled (WinJS.Promise.any).

This is where using WinJS.Promise.as to wrap potentially known or existing values within promises becomes useful: they can then be combined with other asynchronous promises. In other words, promises provide a unified way to deal with values whether they’re delivered synchronously or asynchronously.

Promises also keep everything much simpler when we start working with the full promise relationship, as described earlier. For one, promises provide a structure wherein multiple consumers can each have their own completed handlers attached to the same promise. A real promise class—unlike the simple ones we’ve been working with—internally maintains a list of completed handlers and calls all of them when the value is available.

Furthermore, when error and progress handlers enter into the picture, as well as the ability to cancel an async operation through its promise, managing the differences between various async APIs becomes exceptionally cumbersome. Promises standardize all that, including the ability to manage multiple completed/error/progress callbacks along with a consistent cancel method.

Let’s now look at a more complete promise construct, which will help us understand and appreciate what WinJS provides in its WinJS.Promise class!

The Full Promise Construct

Supporting the full promise relationship means that whatever class we use to implement a promise must provide additional capabilities beyond what we’ve seen so far:

• Support for error and (if appropriate) progress handlers.

• Support for multiple calls to then—that is, the promise must maintain an arbitrary number of handlers and share results between multiple consumers.

• Support for cancellation.

• Support for the ability to chain promises.

As an example, let’s expand the XhrPromise class from Example #3 to support error and progress handlers through its then method, as well as multiple calls to then. This implementation is also a little more robust (allowing null handlers) and supports a cancel method. It can be found in scenario 4 of the Promises example:

var XhrPromise = function (uri) {

this._req = null;

//Handler lists

this._cList = [];

this._eList = [];

this._pList = [];

this.then = function (completedHandler, errorHandler, progressHandler) {

var firstTime = false;

var that = this;

//Only create one operation for this promise

if (!this._req) {

this._req = new XMLHttpRequest();

firstTime = true;

}

//Save handlers in their respective arrays

completedHandler &&this._cList.push(completedHandler);

errorHandler &&this._eList.push(errorHandler);

progressHandler &&this._pList.push(progressHandler);

this._req.onreadystatechange = function () {

var req = that._req;

if (req._canceled) { return; }

if (req.readyState === 4) { //Complete

if (req.status >= 200 && req.status < 300) {

that._cList.forEach(function (handler) {

handler(req);

});

} else {

that._eList.forEach(function (handler) {

handler(req);

});

}

req.onreadystatechange = function () { };

} else {

if (req.readyState === 3) { //Some data received

that._pList.forEach(function (handler) {

handler(req);

});

}

}

};

//Only start the operation on the first call to then

if (firstTime) {

this._req.open("GET", uri, true);

this._req.responseType = "";

this._req.send();

}

};

this.cancel = function () {

if (this._req != null) {

this._req._canceled = true;

this._req.abort;

}

}

}

The consumer of this promise can now attach multiple handlers, including error and progress as desired:

//Consumer code

var promise = doXhrGet("http://kraigbrockschmidt.com/blog/?feed=rss2");

console.log("promise created");

//Listen to promise with all the handlers (as separate functions for clarity)

promise.then(completedHandler, errorHandler, progressHandler);

console.log("returned from first promise.then call");

//Listen again with a second anonymous completed handler, the same error

//handler, and a null progress handler to test then's reentrancy.

promise.then(function (results) {

console.log("second completed handler called, response length = " + results.response.length);

}, errorHandler, null);

console.log("returned from second promise.then call");

function completedHandler (results) {

console.log("operation complete, response length = " + results.response.length);

}

function errorHandler (err) {

console.log("error in request");

}

function progressHandler (partialResult) {

console.log("progress, response length = " + partialResult.response.length);

}

As you can see, the first call to then uses distinct functions; the second call just uses an inline anonymous complete handler and passes null as the progress handler.

Running this code, you’ll see that we pass through all the consumer code first and the first call to thenstarts the operation. The progress handler will be called a number of times and then the completed handlers. The resulting output is as follows (the numbers might change depending on the current blog posts):

promise created

returned from first promise.then call

returned from second promise.then call

progress, response length = 4092

progress, response length = 8188

progress, response length = 12284

progress, response length = 16380

progress, response length = 20476

progress, response length = 24572

progress, response length = 28668

progress, response length = 32764

progress, response length = 36860

progress, response length = 40956

progress, response length = 45052

progress, response length = 49148

progress, response length = 53244

progress, response length = 57340

progress, response length = 61436

progress, response length = 65532

progress, response length = 69628

progress, response length = 73724

progress, response length = 73763

operation complete, response length = 73763

second completed handler called, response length = 73763

In the promise, you can see that we’re using three arrays to track all the handlers sent to then and iterate through those lists when making the necessary callbacks. Note that because there can be multiple consumers of the same promise and the same results must be delivered to each, results are considered immutable. That is, consumers cannot change those results.

As you can imagine, the code to handle lists of handlers is going to look pretty much the same in just about every promise class, so it makes sense to have some kind of standard implementation into which we can plug the specifics of the operation. As you probably expect by now,WinJS.Promise provides exactly this, as well as cancellation, as we’ll see later.

Our last concern is supporting the ability to chain promises. Although any number of asynchronous operations can run simultaneously, it’s a common need that results from one operation must be obtained before the next operation can begin—namely, when those results are the inputs to the next operation. As we saw in Chapter 2, “QuickStart,” this is frequently encountered when doing file I/O in WinRT, where you need obtain a StorageFile object, open it, act on the resulting stream, and then flush and close the stream, all of which are async operations. The flow of such operations can be illustrated as follows:

images

The nesting and chaining constructs that we saw in Chapter 3 can accommodate this need equally, but let’s take a closer look at both.

Nesting Promises

One way to perform sequential async operations is to nest the calls that start each operation within the completed handler of the previous one. This actually doesn’t require anything special where the promises are concerned.

To see this, let’s expand upon that bit of UI-thread-blocking code from Example #2 that did a bunch of counting and turn it into an async operation—see scenario 5 of the Promises example:

function calculateIntegerSum(max, step) {

return new IntegerSummationPromise(max, step);

}

var IntegerSummationPromise = function (max, step) {

this._sum = null; //null means we haven't started the operation

this._cancel = false;

//Error conditions

if (max < 1 || step < 1) {

return null;

}

//Handler lists

this._cList = [];

this._eList = [];

this._pList = [];

this.then = function (completedHandler, errorHandler, progressHandler) {

//Save handlers in their respective arrays

completedHandler &&this._cList.push(completedHandler);

errorHandler &&this._eList.push(errorHandler);

progressHandler &&this._pList.push(progressHandler);

var that = this;

function iterate(args) {

for (var i = args.start; i < args.end; i++) {

that._sum += i;

};

if (i >= max) {

//Complete--dispatch results to completed handlers

that._cList.forEach(function (handler) {

handler(that._sum);

});

} else {

//Dispatch intermediate results to progress handlers

that._pList.forEach(function (handler) {

handler(that._sum);

});

//Do the next cycle

setImmediate(iterate, { start: args.end, end: Math.min(args.end + step, max) });

}

}

//Only start the operation on the first call to then

if (this._sum === null) {

this._sum = 0;

setImmediate(iterate, { start: 0, end: Math.min(step, max) });

}

};

this.cancel = function () {

this._cancel = true;

}

}

The IntegerSummationPromiseclass here is structurally similar to the XhrPromise class in scenario 4 to support multiple handlers and cancellation. Its asynchronous nature comes from using setImmediate to break up its computational cycles (meaning that it’s still running on the UI thread; we’d have to use a web worker to run on a separate thread).

To make sequential async operations interesting, let’s say we get our inputs for calculateIntegerSum from the following function (completely contrived, of course, with a promise that doesn’t support multiple handlers):

function getDesiredCount() {

return new NumberPromise();

}

var NumberPromise = function () {

this._value = 5000;

this.then = function (completedHandler) {

setTimeout(completedHandler, 100, this._value);

}

}

The calling (consumer) code looks like this, where I’ve eliminated any intermediate variables and named functions:

getDesiredCount().then(function (count) {

console.log("getDesiredCount produced " + count);

calculateIntegerSum(count, 500).then(function (sum) {

console.log("calculated sum = " + sum);

},

null, //No error handler

//Progress handler

function (partialSum) {

console.log("partial sum = " + partialSum);

});

});

console.log("getDesiredCount.then returned");

The output of all this appears below, where we can see that the consumer code first executes straight through. Then the completed handler for the first promise is called, in which we start the second operation. That computation reports progress before delivering its final results:

getDesiredCount.then returned

getDesiredCount produced 5000

partial sum = 124750

partial sum = 499500

partial sum = 1124250

partial sum = 1999000

partial sum = 3123750

partial sum = 4498500

partial sum = 6123250

partial sum = 7998000

partial sum = 10122750

calculated sum = 12497500

Although the consumer code above is manageable with one nested operation, nesting gets messy when more operations are involved:

operation1().then(function (result1) {

operation2(result1).then(function (result2) {

operation3(result2).then(function (result3) {

operation4(result3).then(function (result4) {

operation5(result4).then(function (result5) {

//And so on

});

});

});

});

});

Imagine what this would look like if all the completed handlers did other work between each call! It’s very easy to get lost amongst all the braces and indents.

For this reason, real promises can also be chained in a way that makes sequential operations cleaner and easier to manage. When more than two operations are involved, chaining is typically the preferred approach.

Chaining Promises

Chaining is made possible by a couple of requirements that a part of the Promises/A spec places on the then function:

This function [then] should return a new promise that is fulfilled when the given [completedHandler] or errorHandler callback is finished. The value returned from the callback handler is the fulfillment value for the returned promise.

Parsing this, it means that any implementation of then must return a promise whose result is the return value of the completed handler given to then (which is particular for each call to then). With this characteristic, we can write consumer code in a chained manner that avoids indentation nightmares:

operation1().then(function (result1) {

return operation2(result1)

}).then(function (result2) {

return operation3(result2);

}).then(function (result3) {

return operation4(result3);

}).then(function (result4) {

return operation5(result4)

}).then(function (result5) {

//And so on

});

This structure makes it easier to read the sequence and is generally easier to work with. There’s a somewhat obvious flow from one operation to the next, where the return for each promise in the chain is essential. Applying this to the nesting example in the previous section (dropping all but the completed hander), we have the following:

getDesiredCount().then(function (count) {

return calculateIntegerSum(count, 500);

}).then(function (sum) {

console.log("calculated sum = " + sum);

});

Conceptually, when we write chained promises like this, we can conveniently think of the return value from one completed handler as the promise that’s involved with the next thenin the chain: the result from calculateIntegerSum shows up as theargument sumin the next completed handler. We went over this concept in detail in Chapter 2.

However, at the point that getDesiredCount.then returns, we haven’t even started calculate-IntegerSum yet. This means that whatever promise is returned from getDesiredCount.then is some other intermediary promise. This intermediary has its own then method and can receive its owncompleted, error, and progress handlers. But instead of waiting directly for some arbitrary asynchronous operation to finish, this intermediate promise is instead waiting on the results of the completed handler given to getDesiredCount.then. That is, the intermediate promise is a child or subsidiary of the promise that created it, such that it can manage its relationship on the parent’s completed handler.

Looking back at the code from scenario 5 in the last section, you’ll see that none of our then implementations return anything (and are thus incomplete according to the spec). What would it take to make it right?

Simplifying the matter for the moment by not supporting multiple calls to then, a promise class such as NumberPromise would look something like this:

var NumberPromise = function () {

this._value = 1000;

this.then = function (completedHandler) {

setTimeout(valueAvailable, 100, this._value);

var that = this;

function valueAvailable(value) {

var retVal = completedHandler(value);

that._innerPromise.complete(retVal);

}

var retVal = new InnerPromise();

this._innerPromise = retVal;

return retVal;

}

}

Here, thencreates an instance of a promise to which we pass whatever our completed handler gives us. That extra InnerPromise.completemethod is the private communication channel through which we tell that inner promise that it can fulfill itself now, which means it calls whatever completed handlers it received in its own then.

So InnerPromisemight start to look something like this (this is not complete):

var InnerPromise = function (value) {

this._value = value;

this._completedHandler = null;

var that = this;

//Internal helper

this._callComplete = function (value) {

that._completedHandler && that._completedHandler(value);

}

this.then = function (completedHandler) {

if (that._value) {

that._callComplete(that._value);

} else {

that._completedHandler = completedHandler;

}

};

//This tells us we have our fulfillment value

this.complete = function (value) {

that._value = value;

that._callComplete(value);

}

}

That is, we provide a then of our own (still incomplete), which will call its given handler if the value is already known; otherwise it saves the completed handler away (supporting only one such handler). We then assume that our parent promise calls the complete method when it gets a return value from whatever completed handler it’s holding. When that happens, this InnerPromise object can then fulfill itself.

So far so good. However, what happens when the parameter given to complete is itself a promise? That means this InnerPromise must wait for that other promise to finish, using yet another completed handler. Only then can it fulfill itself. Thus, we need to do something like this withinInnerPromise:

//Test if a value is a promise

function isPromise(p) {

return (p && typeof p === "object" && typeof p.then === "function");

}

//This tells us we have our fulfillment value

this.complete = function (value) {

that._value = value;

if (isPromise(value)) {

value.then(function (finalValue) {

that._callComplete(value);

})

} else {

that._callComplete(value);

}

}

We’re on a roll now. With this implementation, the consumer code that chains getDesiredCount and calculateIntegerSum works just fine, where the value of sum passed to the second completed handler is exactly what comes back from the computation.

But we still have a problem: InnerPromise.then does not itself return a promise, as it should, meaning that the chain dies right here. As such, we cannot chain another operation onto the sequence.

What should InnerPromise.then return? Well, in the case where we already have the fulfillment value, we can just return ourselves (which is in the variable that). Otherwise we need to create yet another InnerPromise that’s wired up just as we did inside NumberPromise.

this._callComplete = function (value) {

if (that._completedHandler) {

var retVal = that._completedHandler(value);

that._innerPromise.complete(retVal);

}

}

this.then = function (completedHandler) {

if (that._value) {

var retVal = that._callComplete(that._value);

that._innerPromise.complete(retVal);

return that;

} else {

that._completedHandler = completedHandler;

//Create yet another inner promise for our return value

var retVal = new InnerPromise();

this._innerPromise = retVal;

return retVal;

}

};

With this in place, InnerPromise supports the kind of chaining we’re looking for. You can see this in scenario 6 of the Promises example. In this scenario you’ll find two buttons on the page. The first runs this condensed consumer code:

getDesiredCount().then(function (count) {

return calculateIntegerSum(count, 500);

}).then(function (sum1) {

console.log("calculated first sum = " + sum1);

return calculateIntegerSum(sum1, 500);

}).then(function (sum2) {

console.log("calculated second sum = " + sum2);

});

where the output is:

calculated first sum = 499500

calculated second sum = 124749875250

The second button runs the same consumer code but with explicit variables for the promises. It also turns on noisy logging from within the promise classes so that we can see everything that’s going on. For this purpose, each promise class is tagged with an identifier so that we can keep track of which is which. I won’t show the code, but the output is as follows:

p1 obtained, type = NumberPromise

InnerPromise1 created

p1.then returned, p2 obtained, type = InnerPromise1

InnerPromise1.then called

InnerPromise1.then creating new promise

InnerPromise2 created

p2.then returned, p3 obtained, type = InnerPromise2

InnerPromise2.then called

InnerPromise2.then creating new promise

InnerPromise3 created

p3.then returned (end of chain), returned promise type = InnerPromise3

NumberPromise completed.

p1 fulfilled, count = 1000

InnerPromise1.complete method called

InnerPromise1 calling IntegerSummationPromise.then

IntegerSummationPromise started

IntegerSummationPromise completed

IntegerSummationPromise fulfilled

InnerPromise1 calling completed handler

p2 fulfilled, sum1 = 499500

InnerPromise2.complete method called

InnerPromise2 calling IntegerSummationPromise.then

IntegerSummationPromise started

IntegerSummationPromise completed

IntegerSummationPromise fulfilled

InnerPromise2 calling completed handler

p3 fulfilled, sum2 = 124749875250

InnerPromise3.complete method called

InnerPromise3 calling completed handler

This log reveals what’s going on in the chain. Because each operation in the sequence is asynchronous, we don’t have any solid values to pass to any of the completed handlers yet. But to execute the chain of then calls—which all happens a synchronous sequence—there has to be some promise in there to do the wiring. That’s the purpose of each InnerPromise instance. So, in the first part of this log you can see that we’re basically creating a stack of these InnerPromise instances, each of which is waiting on another.

Once all the then methods return and we yield the UI thread, the async operations can start to fulfill themselves. You can see that the NumberPromise gets fulfilled, which means that InnerPromise1 can be fulfilled with the return value from our first completed handler. That happens to be an Integer-SummationPromise, so InnerPromise1 attaches its own completed handler. When that handler is called, InnerPromise1 can call the second completed handler in the consumer code. The same thing then happens again with InnerPromise2, and so on, until the stack of inner promises are all fulfilled. It’s at this point that we run out of completed handlers to call and the chain comes to an end.

In short, having then methods return another promise to allow chaining basically means that a chain of async operations builds a stack of intermediate promises to manage the connections between as-yet-unfulfilled promises and their completed handlers. As results start to come in, that stack is unwound such that the intermediate results are passed to the appropriate handler so that the next async operation can begin.

Let me be very clear about what we’ve done so far: the code above shows how chaining really works in the guts of promises, and yet we still have a number of unsolved problems:

• InnerPromise.then can manage only a single completed handler and doesn’t provide for error and progress handlers.

• There’s no provision for handling exceptions in a completed handler, as specified by Promises A.

• There’s no provision for cancellation of the chain—namely, that canceling the promise produced by the chain as a whole should also cancel all the other promises involved.

• Some code structures are repeated, so some kind of consolidation seems appropriate.

• This code hasn’t been fully tested.

I will openly admit that I’m not right kind of developer to solve such problems—I’m primarily a writer! A number of subtle issues start to arise when you put this kind of thing into practice, but fortunately some software engineers adore this kind of a challenge, and fortunately a number of them work in the WinJS team. As a result, they’ve done all the hard work for us within the WinJS.Promise class. And we’re now ready to see—and fully appreciate!—what that library provides.

Promises in WinJS (Thank You, Microsoft!)

When writing Windows Store apps in JavaScript, promises pop up anytime an asynchronous API is involved and even at other times. Those promises all meet the necessary specifications, because their underlying classes are supplied by the operating system, which is to say, WinJS. From the consuming code’s point of view, then, these promises can be used to their fullest extent possible: nested, chained, joined, and so forth. These promises can also be trusted to manage any number of handlers, to correctly process errors, and basically to handle any other subtleties that might arise.

I say all this because the authors of WinJS have gone to great effort to provide highly robust and complete promise implementations, and this means there is really no need to implement custom promise classes of your own. WinJS provides an extensible means to wrap any kind of async operation within a standardized and well-tested promise structure, so you can focus on the operation and not on the surrounding construct.

We’ve already covered most of the consumer-side WinJS surface area for promises in Chapter 3, including all the static methods of the WinJS.Promise object: is, theneach, as, timeout, join, and any. The latter of these are basically shortcuts to create promises for common scenarios. Scenario 7 of the Promises example gives a short demonstration of many of these.

In Chapter 4 we also saw the WinJS.xhr function that wraps XMLHttpRequest operations in a promise, which is a much better choice than the wrapper we have in scenario 4 of the Promises example (though we might go all the way and use Windows.Web.Http.HttpClient instead). Here, in fact, is the equivalent (and condensed) consumer code from scenario 7 that matches that of scenario 4:

var promise = WinJS.xhr("http://kraigbrockschmidt.com/blog/?feed=rss2");

promise.then(function (results) {

console.log("complete, response length = " + results.response.length);

},

function (err) {

console.log("error in request: " + JSON.stringify(err));

},

function (partialResult) {

console.log("progress, response length = " + partialResult.response.length);

});

What’s left for us to discuss is the instantiable WinJS.Promise class itself, with which you can, as an originator, easily wrap any async operation of your own in a full promise construct.

Note The entire source code for WinJS promises can be found in its base.js file, accessible through any app project that has a reference to WinJS. (In Visual Studio’s Solution Explorer, expand References > Windows Library For JavaScript > js under a project, and you’ll see base.js.)

The WinJS.Promise Class

Simply said,WinJS.Promise is a generalized promise class that allows you to focus on the nature of a custom async operation, leaving WinJS.Promise to deal with the promise construct itself, including implementations of then and cancel methods, management of handlers, and handling complex cancellation processes involved with promise chains.

As a comparison, in scenario 6 of the Promises example we created distinct promise classes that the getDesiredCountand calculateIntegerSum functions use to implement their async behavior. All that code got to be rather intricate, which means it will be hard to debug and maintain! With WinJS.Promise, we can dispense with those separate promise classes altogether. Instead, we just implement the operations directly within a function like calculateIntegerSum. This is how it now looks in scenario 8 (omitting bits of code to handle errors and cancellation, and pulling in the code from default.js where the implementation is shared with other scenarios):

function calculateIntegerSum(max, step) {

//The WinJS.Promise constructor's argument is a function that receives

//dispatchers for completed, error, and progress cases.

return new WinJS.Promise(function (completeDispatch, errorDispatch, progressDispatch) {

var sum = 0;

function iterate(args) {

for (var i = args.start; i < args.end; i++) {

sum += i;

};

if (i >= max) {

//Complete--dispatch results to completed handlers

completeDispatch(sum);

} else {

//Dispatch intermediate results to progress handlers

progressDispatch(sum);

setImmediate(iterate, { start: args.end, end: Math.min(args.end + step, max) });

}

}

setImmediate(iterate, { start: 0, end: Math.min(step, max) });

});

}

Clearly, this function still returns a promise, but it’s an instance of WinJS.Promise that’s essentially been configured to perform a specific operation. That “configuration,” if you will, is supplied by the function we passed to the WinJS.Promise constructor, referred to as the initializer. The core of this initializer function does exactly what we did with IntegerSummationPromise.then in scenario 6. The great thing is that we don’t need to manage all the handlers nor the details of returning another promise from then. That’s all taken care of for us. Whew!

All we need is a way to tell WinJS.Promise when to invoke the completed, error, and progress handlers it’s managing on our behalf. That’s exactly what’s provided by the three dispatcher arguments given to the initializer function. Calling these dispatchers will invoke whatever handlers the promise has received through then or done, just like we did manually in scenario 6. And again, we no longer need to worry about the structure details of creating a proper promise—we can simply concentrate on the core functionality that’s unique to our app.

By the way, a helper function like WinJS.Promise.timeout also lets us eliminate a custom promise class like the NumberPromise we used in scenario 6 to implement the getDesiredCount. We can now just do the following (taken from scenario 8, which matches the quiet output of scenario 6 with a lot less code!):

function getDesiredCount() {

return WinJS.Promise.timeout(100).then(function () { return 1000; });

}

To wrap up, a couple of other notes on WinJS.Promise:

• Doing new WinJS.Promise()(with no parameters) will throw an exception: an initializer function is required.

• If you don’t need the errorDispatcher and progressDispatcher methods, you don’t need to declare them as arguments in your function. JavaScript is nice that way!

• Any promise you get from WinJS (or WinRT for that matter) has a standard cancel method that cancels any pending async operation within the promise, if cancellation is supported. It has no effect on promises that contain already-known values.

• To support cancellation, theWinJS.Promise constructor also takes an optional second argument: a function to call if the promise’scancelmethod is called. Here you halt whatever operation is underway. ThefullcalculateIntegerSumfunction of scenario 8, for example (again, it’s in default.js), has a simple function to set a_cancel variable that the iteration loop checks before calling its nextsetImmediate.

Originating Errors with WinJS.Promise.WrapError

In Chapter 3 we learned about handling async errors as a consumer of promises and the role of the done method vs. then. When originating a promise, we need to make sure that we cooperate with how all that works.

When implementing an async function, you must handle two different error conditions. One is obvious: you encounter something within the operation that causes it to fail, such as a network timeout, a buffer overrun, the inability to access a resource, and so on. In these cases you call the error dispatcher (the second argument given to your initialization function by the WinJS.Promise constructor), passing an error object that describes the problem. That error object is typically created with WinJS.ErrorFromName (using new), using an error name and a message, but this is not a strict requirement. WinJS.xhr, for example, passes the request object directly to the error handler because that object contains much richer information already.

To contrive an example, if calculateIntegerSum(from default.js) encountered some error while processing its operation, it would do the following:

if (false/* replace with any necessary error check -- we don't have any here*/) {

errorDispatch(new WinJS.ErrorFromName("calculateIntegerSum", "error occurred"));

}

The other error condition is more interesting. What happens when a function that normally returns a promise encounters a problem such that it cannot create its usual promise? It can’t just return null, because that would make it very difficult to chain promises together. What it needs to do instead is return a promise that already contains an error, meaning that it will immediately call any error handlers given to its then.

For this purpose, WinJS has a special function WinJS.Promise.wrapErrorwhose argument is an error object (again typically a WinJS.ErrorFromName). wrapError creates a promise that has no fulfillment value and will never call a completed handler. It will pass its error to any error handler only if you call then or done. Still, its then function must yet return a promise itself; in this case it returns a promise whose fulfillment value is the error object.

For example, if calculateIntegerSumreceives maxorstep arguments that are less than 1, it has to fail and can just return a promise from wrapError (see default.js):

if (max < 1 || step < 1) {

var err = new WinJS.ErrorFromName("calculateIntegerSum (scenario 7)"

, "max and step must be 1 or greater");

return WinJS.Promise.wrapError(err);

}

The consumer code looks like this, as found in scenario 8:

calculateIntegerSum(0, 1).then(function (sum) {

console.log("calculateIntegerSum(0, 1) fulfilled with " + sum);

}, function (err) {

console.log("calculateIntegerSum(0, 1) failed with error: '" + err.message +"'");

return"value returned from error handler";

}).then(function (value) {

console.log("calculateIntegerSum(0, 1).then fulfilled with: '" + value + "'");

});

Some tests in scenario 8 show this output:

calculateintegersum(0, 1) failed with error: 'max and step must be 1 or greater'

calculateIntegerSum(0, 1).then fulfilled with: 'value returned from error handler'

Another way that an asynchronous operation can fail is by throwing an exception rather than calling the error dispatcher directly. This is important with async WinRT APIs, as those exceptions can occur deep down in the operating system. WinJS accommodates this by wrapping the exception itself into a promise that can then be involved in chaining. The exception just shows up in the consumer’s error handler.

Speaking of chaining, WinJS makes sure that errors are propagated through the chain to the error handler given to the last then/done in the chain, allowing you to consolidate your handling there. This is why promises from wrapError are themselves fulfilled with the error value, which they send to their completed handlers instead of the error handlers.

However, because of some subtleties in the JavaScript projection layer for the WinRT APIs, exceptions thrown from async operations within a promise chain will get swallowed and will not surface in that last error handler. Mind you, this doesn’t happen with a single promise and a single call to then, nor with nested promises, but most of the time the consumer is chaining multiple operations. Such is why we have the done method alongside then. By using this in the consumer at the end of a promise chain, you ensure that any error in the chain is propagated to the error handler given to done.

Some Interesting Promise Code

Finally, now that we’ve thoroughly explored promises both in and out of WinJS, we’re ready to dissect various pieces of code involving promises and understand exactly what they do, beyond the basics of chaining that we’ve seen.

Delivering a Value in the Future: WinJS.Promise.timeout

To start with a bit of review, the simple WinJS.Promise.timeout(<n>).then(function () { <value> }); pattern delivers a known value at some time in the future:

var p = WinJS.Promise.timeout(1000).then(function () { return 12345; });

Of course, you can return another promise inside the first completed handler and chain more then calls, which is just an example of standard chaining.

Internals of WinJS.Promise.timeout

The first two cases of WinJS.Promise.timeout, timeout() and timeout(n), are implemented as follows, using a new instance of WinJS.Promise where the initializer calls either setImmediate or setTimeout(n):

// Used for WinJS.Promise.timeout() and timeout(n)

function timeout(timeoutMS) {

var id;

return new WinJS.Promise(

function (c) {

if (timeoutMS) {

id = setTimeout(c, timeoutMS);

} else {

setImmediate(c);

}

},

function () {

if (id) {

clearTimeout(id);

}

}

);

}

The WinJS.Promise.timeout(n, p) form is more interesting. As before, it fulfills p if it happens within n milliseconds; otherwise pis canceled. Here’s the core of its implementation:

function timeoutWithPromise(timeout, promise) {

var cancelPromise = function () { promise.cancel(); }

var cancelTimeout = function () { timeout.cancel(); }

timeout.then(cancelPromise);

promise.then(cancelTimeout, cancelTimeout);

return promise;

}

The timeoutargument comes from calling WinJS.Promise.timeout(n), and promiseis the p from WinJS.Promise.timeout(n, p). As you can see, promiseis just returned directly. However, see how the promise and the timeout are wired together. If the timeout promise is fulfilled first, it callscancelPromise to cancel promise>. On the flipside, if promiseis fulfilled first or encounters an error, it calls cancelTimeout to cancel the timer.

Parallel Requests to a List of URIs

If you need to retrieve information from multiple URIs in parallel, here’s a little snippet that gets a WinJS.xhr promise for each and joins them together:

// uris is an array of URI strings

WinJS.Promise.join(

uris.map(function (uri) { return WinJS.xhr({ url: uri }); })

).then(function (results) {

results.forEach(function (result, i) {

console.log("uri: " + uris[i] + ", " + result);

});

});

The array map method simply generates a new array with the results of the function you give it applied to each item in the original array. This new array becomes the argument to join, which is fulfilled with an array of results.

You can of course replace WinJS.xhr with Windows.Web.Http.HttpClient.get* methods (see Chapter 4 in the section “Using Windows.Web.Http.HttpClient”) or use any other array of input values for uris and any other async method for that matter.

Parallel Promises with Sequential Results

WinJS.Promise.join and WinJS.Promise.any work with parallel promises—that is, with parallel async operations. The promise returned by join will be fulfilled when all the promises in an array are fulfilled. However, those individual promises can themselves be fulfilled in any given order. What if you have a set of operations that can execute in parallel but you want to process their results in a well-defined order—namely, the order that their promises appear in an array?

The trick is to basically join each subsequent promise to all of those that come before it, and the following bit of code does exactly that. Here, list is an array of values of some sort that are used as arguments for some promise-producing async call that I call doOperation:

list.reduce(function callback (prev, item, i) {

var result = doOperation(item);

return WinJS.Promise.join({ prev: prev, result: result}).then(function (v) {

console.log(i + ", item: " + item+ ", " + v.result);

});

})

To understand this code, we have to first understand how the array’s reduce method works, because it’s slightly tricky. For each item in the array, reduce calls the function you provide as its argument, which I’ve named callback for clarity. This callback receives four arguments (only three of which are used in the code):

• prev The value that’s returned from the previous call to callback. For the first item, prev is null.

• item The current value from the array.

• i The index of item in the list.

• source The original array.

It’s also important to remember that WinJS.Promise.join can accept a list in the form of an object, as shown here, as well as an array (it uses Object.keys(list).forEach to iterate).

To make this code clearer, it helps to write it out with explicit promises:

list.reduce(function callback (prev, item, i) {

var opPromise = doOperation(item);

var join = WinJS.Promise.join({ prev: prev, result: opPromise});

return join.then(function completed (v) {

console.log(i + ", item: " + item+ ", " + v.result);

});

})

By tracing through this code for a few items in list, we’ll see how we build the sequential dependencies.

For the first item in the list, we get its opPromise and then join it with whatever is contained in prev. For this first item prev is null, so we’re essentially joining, to express it in terms of an array, [WinJS.Promise.as(null), opPromise]. But notice that we’re not returning join itself. Instead, we’re attaching a completed handler (which I’ve called completed) to that join and returning the promise from its then.

Remember that the promise returned from then will be fulfilled when the completed handler returns. This means that what we’re returning from callback is a promise that’s not completed until the first item’s completed handler has processed the results from opPromise. And if you look back at the result of a join, it’s fulfilled with an object that contains the results from the promises in the original list. That means that the fulfillment value v will contain both a prev property and a result property, the values of which will be the values from prev (which is null) andopPromise. Therefore v.result is the result of opPromise.

Now see what happens for the next item in list. When callback is invoked this time, prev contains the promise from the previous join.then. So, in the second pass through callback we create a new join of opPromise2 and opPromise1.then. As a result, this join will not complete until both opPromise2 is fullfilled and the completed handler for opPromise1 returns. Voila! The completed2 handler we now attach to this join will not be called until after completed1 has returned.

In short, the same dependencies continue to be built up for each item in list—the promise from join.then for item n will not be fulfilled until completedn returns, and we’ve guaranteed that the completed handlers will be called in the same sequence as list.

A working example of this construct using calculateIntegerSum and an array of numbers can be found in scenario 9 of the Promises example. The numbers are intentionally set so that some of the calculations will finish before others, but you can see that the results are delivered in order.

Constructing a Sequential Promise Chain from an Array

A similar construct to the one in the previous section is to use the array’s reduce method to build up a promise chain from an array of input arguments such that each async operation doesn’t start before the previous one is complete. Scenario 10 of the Promises example demonstrates this:

//This just avoids having the prefix everywhere

var calculateIntegerSum = App.calculateIntegerSum;

//This op function attached other arguments to each call

var op = function (arg) { return calculateIntegerSum(arg, 100); };

//The arguments we want to process

var args = [1000000, 500000, 300000, 150000, 50000, 10000];

//This code creates a parameterized promise chain from the array of args and the async call

//in op. By using WinJS.Promise.as for the initializer we can just call p.then inside

//the callback.

var endPromise = args.reduce(function (p, arg) {

return p.then(function (r) {

//The first result from WinJS.Promise.as will be undefined, so skip logging

if (r !== undefined) { App.log("operation completed with results = " + r) };

return op(arg);

});

}, WinJS.Promise.as());

//endPromise is fulfilled with the last operation's results when the whole chain is complete.

endPromise.done(function (r) {

App.log("Final promise complete with results = " + r);

});

PageControlNavigator._navigating (Page Control Rendering)

The final piece of code we’ll look at in this appendix comes from the navigator.js file that’s included with the Visual Studio templates that employ WinJS page controls. This is an event handler for the WinJS.Navigation.onnavigating event, and it performs the actual loading of the target page (using WinJS.UI.Pages.render to load it into a newly created div, which is then appended to the DOM) and unloading of the current page (by removing it from the DOM):

_navigating: function (args) {

var newElement = this._createPageElement();

var parentedComplete;

var parented = new WinJS.Promise(function (c) { parentedComplete = c; });

this._lastNavigationPromise.cancel();

this._lastNavigationPromise = WinJS.Promise.timeout().then(function () {

return WinJS.UI.Pages.render(args.detail.location, newElement,

args.detail.state, parented);

}).then(function parentElement(control) {

var oldElement = this.pageElement;

if (oldElement.winControl && oldElement.winControl.unload) {

oldElement.winControl.unload();

}

WinJS.Utilities.disposeSubTree(this._element);

this._element.appendChild(newElement);

this._element.removeChild(oldElement);

oldElement.innerText = "";

parentedComplete();

}.bind(this));

args.detail.setPromise(this._lastNavigationPromise);

},

First of all, this code cancels any previous navigation that might be happening, then creates a new one for the current navigation. The args.detail.setPromise call at the end is the WinJS deferral mechanism that’s used in a number of places. It tells WinJS.Navigation.onnavigating to defer its default process until the given promise is fulfilled. In this case, WinJS waits for this promise to be fulfilled before raising the subsequent navigated event.

Anyway, the promise in question here is what’s produced by a WinJS.Promise.timeout().-then().then() sequence. Starting with a timeout() promise means that the process of rendering a page control first yields the UI thread via setImmediate, allowing other work to complete before we start the rendering process.

After yielding, we then enter into the first completed handler that starts rendering the new page control into newElement with WinJS.UI.Pages.render. Rendering is an async operation itself (it involves a file loading operation, for one thing), so render returns a promise. At this point,newElement is an orphan—it’s not yet part of the DOM, just an object in memory—so all this rendering is just a matter of loading up the page control’s contents and building that standalone chunk of DOM.

When render completes, the next completed handler in the chain, which is actually named parentElement (“parent” in this case being a verb), receives the newly loaded page control object. This code doesn’t make use of this argument, however, because it knows that it’s the contents ofnewElement (newElement.winControl, to be precise). So we now unload any page control that’s currently loaded (that.pageElement.winControl), calling its unload method, if available, and also making sure to free up event listeners and whatnot with WinJS.Utilities.disposeSubtree. Then we can attach the new page’s contents to the DOM and remove the previous page’s contents. This means that the new page contents will appear in place of the old the next time the rendering engine gets a chance to do its thing.

Finally, we call this function parentedComplete. This last bit is really a wiring job so that WinJS will not invoke the new page’s ready method until it’s been actually added to the DOM. This means that we need a way for WinJS to hold off making that call until parenting has finished.

Earlier in _navigating, we created a parentedPromise variable, which was then given as the fourth parameter to WinJS.UI.Pages.render. This parentedPromise is very simple: we’re just calling new WinJS.Promise and doing nothing more than saving its completed dispatcher in theparented-Complete variable, which is what we call at the end of the process.

For this to serve any purpose, of course, someone needs to call parentedPromise.then and attach a completed handler. A WinJS page control does this, and all its completed handler does is call ready. Here’s how it looks in base.js:

this.renderComplete.then(function () {

return parentedPromise;

}).then(function Pages_ready() {

that.ready(element, options);

})

In the end, this whole _navigating code is just saying, “After yielding the UI thread, asynchronously load up the new page’s HTML, add it to the DOM, clean out and remove the old page from the DOM, and tell WinJS that it can call the new page’s ready method, because we’re not calling it directly ourselves.”

Bonus: Deconstructing the ListView Batching Renderer

The last section of Chapter 7, titled “Template Functions (Part 2): Optimizing Item Rendering,” talks about the multistage batching renderer found in scenario 1 of the HTML ListView optimizing performance sample. The core of the renderer is a function named thumbnailBatch, whose purpose is to return a completed handler for an async promise chain in the renderer:

renderComplete: itemPromise.then(function (i) {

item = i;

// ...

return item.ready;

}).then(function () {

return item.loadImage(item.data.thumbnail);

}).then(thumbnailBatch()

).then(function (newimg) {

img = newimg;

element.insertBefore(img, element.firstElementChild);

return item.isOnScreen();

}).then(function (onscreen) {

//...

})

To understand how this works, we first need a little more background as to what we’re trying to accomplish. If we just had a ListView with a single item, various loading optimizations wouldn’t be noticeable. But ListViews typically have many items, and the rendering function is called for each one. In the multistage renderer described in Chapter 7, the rendering of each item kicks off an async item.loadImage operation to download its thumbnail from an arbitrary URI, and each operation can take an arbitrary amount of time. For the list as a whole, we might have a bunch of simultaneous loadImage calls going on, with the rendering of each item waiting on the completion of its particular thumbnail. So far so good.

An important characteristic that’s not at all visible in the multistage renderer, however, is that the img element for the thumbnail is already in the DOM, and the loadImage function will set that image’s src attribute as soon as the download has finished. This in turn triggers an update in the rendering engine as soon as we return from the rest of the promise chain.

It’s possible, then, that a bunch of thumbnails could come back to the UI thread within a short amount of time. This will cause excess churn in the rendering engine and poor visual performance. To avoid this churn, we need to create and initialize the img elements before they’re in the DOM, and then we need to add them in batches such that they’re all handled in a single rendering pass.

This is the purpose of the function in the sample called createBatch, which is called just once to produce the oft-used thumbnailBatch function:

var thumbnailBatch;

thumbnailBatch = createBatch();

As shown above, a call to this thumbnailBatch function, as I’ll refer to it from here on, is inserted into the promise chain of the renderer. This purpose of this insertion, given the nature of the batching code that we’ll see shortly, is to group together a set of loaded img elements, releasing them for further processing at suitable intervals. Again, just looking at the promise chain in the renderer, a call to thumbnailBatch()must return a completed handler function that accepts, as a result, whatever loadImage produces (an img element). In this case, loadImage is creating that imgelement for us, unlike the previous multistage renderer that uses one that’s already in the DOM.

Because the call to thumbnailBatch is in a chain, the completed handler it produces must also return a promise whose the fulfillment value (looking at the next step in the chain) must be an img element that can then be added to the DOM as part of a batch.

Now let’s see how that batching works. Here’s the createBatch function in its entirety:

function createBatch(waitPeriod) {

var batchTimeout = WinJS.Promise.as();

var batchedItems = [];

function completeBatch() {

var callbacks = batchedItems;

batchedItems = [];

for (var i = 0; i < callbacks.length; i++) {

callbacks[i]();

}

}

returnfunction () {

batchTimeout.cancel();

batchTimeout = WinJS.Promise.timeout(waitPeriod || 64).then(completeBatch);

var delayedPromise = new WinJS.Promise(function (c) {

batchedItems.push(c);

});

return function (v) {

return delayedPromise.then(function () {

return v;

});

};

};

}

Again, createBatch is called just once and its thumbnailBatch result is called for every item in the list. The completed handler that thumbnailBatch generates is then called whenever a loadImage operation completes.

Such a completed handler might just as easily have been inserted directly into the rendering function, but what we’re trying to do here is coordinate activities across multiple items rather than just on a per-item basis. This coordination is achieved through the two variables created and initialized at the beginning of createBatch: batchedTimeout, initialized as an empty promise, and batchedItems, initialized an array of functions that’s initially empty. createBatch also declares a function, completeBatch, that simply empties batchedItems, calling each function in the array:

function completeBatch() {

//Copy and clear the array so that the next batch can start to accumulate

//while we're processing the previous one.

var callbacks = batchedItems;

batchedItems = [];

for (var i = 0; i < callbacks.length; i++) {

callbacks[i]();

}

}

Now let’s see what happens within thumbnailBatch (the function returned from createBatch), which is again called for each item being rendered. First, we cancel any existing batchedTimeout and immediately re-create it:

batchTimeout.cancel();

batchTimeout = WinJS.Promise.timeout(waitPeriod || 64).then(completeBatch);

The second line shows the future delivery/fulfillment pattern discussed earlier: it says to call completeBatch after a delay of waitPeriod milliseconds (with a default of 64ms). This means that so long as thumbnailBatch is being called again within waitPeriod of a previous call,batchTimeout will be reset to another waitPeriod. And because thumbnailBatch is calledonly after an item.loadImage call completes, we’re effectively saying that any loadImage operations that complete within waitPeriod of the previous one will be included in the same batch. When there’s a gap longer than waitPeriod, the batch is processed (images are added to the DOM) and the next batch begins.

After handling this timeout business, thumbnailBatch creates a new promise that simply pushes the complete dispatcher function into the batchedItems array:

var delayedPromise = new WinJS.Promise(function (c) {

batchedItems.push(c);

});

Remember that a promise is just a code construct, and that’s all we have here. The newly created promise has no async behavior in and of itself: we’re just adding the complete dispatcher function, c, to batchedItems. But, of course, we don’t do anything with the dispatcher untilbatchedTimeout completes (asynchronously), so there is in fact an async relationship here. When the timeout happens and we clear the batch (inside completeBatch), we’ll invoke any completed handlers given elsewhere to delayedPromise.then.

This brings us to the last line of code in createBatch, which is the function that thumbnailBatch actually returns. This function is exactly the completed handler that gets inserted into the renderer’s whole promise chain:

return function (v) {

return delayedPromise.then(function () {

return v;

});

};

In fact, let’s put this piece of code directly into the promise chain so that we can see the resulting relationships:

return item.loadImage(item.data.thumbnail);

}).then(function (v) {

return delayedPromise.then(function () {

return v;

});

).then(function (newimg) {

Now we can see that the argument vis the result of item.loadImage, which is the img element created for us. If we didn’t want to do batching, we could just say return WinJS.Promise.as(v) and the whole chain would still work: v would then be passed on synchronously and show up asnewimg in the next step.

Instead, however, we’re returning a promise from delayedPromise.then that won’t be fulfilled—with v—until the current batchedTimeout is fulfilled. At that time—when again there’s a gap of waitPeriod between loadImage completions—those img elements are delivered to the next step in the chain where they’re added to the DOM.

And that’s it. Now you know!

141 The method could be a propertysetter, of course; the point here is that a method of some kind is necessary for the object to have a trigger for additional action, something that a passive (non-setter) property lacks.

In this context I’ll also share a trick that Chris Sells, who was my manager at Microsoft for a short time, used on me repeatedly. For some given deliverable I owed him, he’d ask, “When will you have it done?” If I said I didn’t know, he’d ask, “When will you know when you’ll have it done?” If I still couldn’t answer that, he’d ask, “When will you know when you’ll know when you’ll have it done?” ad infinitum until he extracted some kind of solid commitment from me!

142 The specification for then, again, stipulates that its return value is a promise that’s fulfilled when the completed handler returns, which is one of the bits that makes the implementation of a promise quite complicated. Clearly, we’re ignoring that part of the definition here; we’ll return to it in “The Full Promise Construct.”