about Promises, given at LondonJS on November 19th, 2012. Photo by Sergiu Bacioiu, CC-BY-NC-2.0, http://www.flickr.com/photos/sergiu_bacioiu/5145619202/
value. In it's simplest form we assign that value to a variable. The operation is synchronous. But this is JavaScript, and we're not often synchronous!
future turn of the event loop, to which you can add handlers before or after the promise is fulfilled, and which always call the handlers with the same value. Photo by Alexandre Normand, CC-BY-2.0, http://www.flickr.com/photos/alexnormand/ 5992512756/
a useful abstraction that comes with its own set of coding patterns. Photo by Eric (illuminaut), CC-BY-NC-SA-2.0, http://www.flickr.com/photos/illuminaut/ 3954750954/
.then(square); // 4 Let's say our function fulfills the promise with a value of 2. We then transform that value through the square method, resulting in 4. But how do we read this value?
4 }); }).then(square) // 64 .then(log); // --> 64 But what if the handler returns a promise instead of a value? The chain will wait for that promise to be resolved.
= getOtherValue(); var q2 = q1.then(function(n){ return m * n; }); return q2; // 2 * 4 }); var p3 = p2.then(square); // 64 p3.then(log); // --> 64 Here's the same example, but with the promises named.
}); Errors are handled by a different method! This means they'll never interfere with your normal handler. In effect there is a second communication channel.
in either of three states: * Pending: waiting to be fulfilled or rejected * Fulfilled: successfully fulfilled with a value * Rejected: failed with a rejection reason A promise can only go from pending to either fulfilled or rejected. Once it's no longer pending its state is frozen. So is its value or reason. Photo by Sergiu Bacioiu, CC-BY-NC-2.0, http://www.flickr.com/photos/sergiu_bacioiu/ 5142895618/
p1.then(function(){ throw new Error("oops"); }); // pending We know add a handler, resulting in a second promise. Because the first promise is still pending, so is the second.The handler we add to p1 throws an error, which means p2 will be in a rejected state.
throw new Error("oops"); }); // rejected Now let's say p1 gets fulfilled. The handler we added to p1 throws an error, which means p2 is in a rejected state.
reason.message; }); // p3 is fulfilled If we then add a handler for that rejection and return a value, we've put p3 in a fulfilled state. Any handler that throws an error puts the returned promise in a rejected state. Any handler that returns a value puts it in the fulfilled state.
reason.message; }); // technically, p3 is still pending… Technically the handler we've added to p2 is invoked in the next turn, which means p3 is still pending until the handler has been executed, at which point p3 will be fulfilled.
and examples I've shown so far are compatible with Promises/A+. This is a clarification of the original Promises/A specification, aimed at describing how promises work in modern day implementations. It's an effort led by Domenic Denicola, who's also worked on Q. The specification is a part of this effort, as is defining a test suite that can be used to test promise libraries. But let's look at using promises with the utilities in Dojo 1.8. <http://promises-aplus.github.com/promises-spec/>
} ); }); But we can also add a rejection handler. The beauty is that you don't have to read documentation to see which argument to request is the success handler, and which is the failure handler. You get a promise, and you know how to deal with promises.
Deferred(); setTimeout(function(){ dfd.resolve("value!"); }, 1000); return dfd.promise; } }); dojo/Deferred defines a class that manages a promise for you. Deferreds should be private, internal values. You do not return them to the calling code. Instead you return the promise that is exposed by the deferred. You can fulfill the promise using the resolve() method, or reject() for rejecting it. It's good practice to start your function with instantiating the deferred, and returning the promise at the very end. This makes it easily recognizable as returning a promise. Deferreds themselves aren't part of the Promises/A+ spec, which is OK since they're for internal use only. Functions should return promises that *do* adhere to the spec. You don't want to return the deferred because calling code shouldn't be able to change state internal to your function.
our handler if unknownResult returns a non-promise value, or pass it to then() if it returns a promise. Note that in the former case, any error thrown by the handler is not caught.
some extra functionality in Dojo's promise implementation. It allows you to send cancelation messages up the promise chain when results are no longer required. Progress updates can be send down the chain without changing the promise state, i.e. allowing you to notify calling code of file uploader status. There are reflection methods for determining the state of a deferred or promise without having to register handlers, debug helpers, and utilities for dealing with multiple promises at once. These features aren't specified by Promises/A+, though I'd like to write compatible specifications for them. Photo by Trey Ratcliff, CC-BY-NC-SA-2.0, http://www.flickr.com/photos/stuckincustoms/ 5896504098/
as to express an algorithm Rejections are part of your API Rethrow unknown rejection reasons I'd like to conclude with some tips on writing effective promise-based code. It's best to keep promise chains shallow. We're still trying to avoid spaghetti code! Name your functions so the promise chain remains readable. And remember that throwing errors can make for a great API . For instance, it's better to throw a NotFoundError than return a null value. In rejection handlers, look for expected errors and handle them, rethrow everything else. Photo by Chang Liu, CC-BY-2.0, http://www.flickr.com/photos/spaceabstract/7329382340/
engineers at State, where we’re building a global opinion network. If you'd like to work in a great team building great things, come talk to me afterwards, or check out https://state.com.
Ginny (ginnerobot) Jeff Kubina Licensed under Creative Commons Attribution-Non-Commercial-Share Alike 3.0 http://creativecommons.org/licenses/by-nc-sa/3.0/ Many, many thanks to the wonderful people on Flickr who licensed their photos under Creative Commons. Photo by Jeff Kubina, http://flickr.com/photos/kubina/903033693/. CC-BY-SA 2.0.