javascript promises
DESCRIPTION
TRANSCRIPT
Promises in JavaScriptso, async For The Win! !!Leszek Gruchała @LeszekGruchala
2
The Pyramid of Doom
step1(function(value1) {
step2(value1, function(value2) {
step3(value2, function(value3) {
step4(value3, function(value4) {
// Do something with value4
});
});
});
});
3
Promises to the rescue!
▪ We get ▪ invocation chaining ▪ error propagation ▪ common error handling ▪ common successful result handling ▪ in progress notification (if Promise supports it) ▪ ability to wrap existing async solutions
4
What makes a Promise?
▪ specification Promises/A+ (thenable) ▪ promise.then(onFulfilled, onRejected, onProgress)
▪ Possible states: ▪ fulfilled ▪ rejected ▪ pending
5
Browser support
▪ Q ▪ When.JS ▪ WinJS ▪ RSVP.JS ▪ jQuery 1.8+ (Deferred Object, Promise) ▪ native (!) with Chrome32+, Opera21+, Firefox29+ ▪ no Safari & mobile browsers
Examples
7
Native invocation
var promise = new Promise(function(resolve, reject) { // do a thing, possibly async, then… if (isOk) { resolve("Stuff worked!"); } else { reject(Error("It broke")); } }); promise.then(function(result) { // "Stuff worked!" }, function(err) { // Error: "It broke" });
8
Q - sequence of invocations
Q.fcall(promisedStep1) .then(promisedStep2) .then(promisedStep3) .then(promisedStep4) .then(function(value4) { // Do something with value4 }).catch(function(error) { // Handle any error from all above steps, if no catch errors will be thrown to the browser // and will block JS code execution }).progress(function() { //optional notification about progress for promises which support this i.e. file upload }).finally(function() { //optional handle success or failure }).done(function() { //everything is done, end chain of invocation });
9
Q - sequence of invocations
//Even if error arises, will wait for other requests to finish Q.allSettled(promises).then(function(results) { results.forEach(function(result) { if (result.state === "fulfilled") { var value = result.value; } else { var reason = result.reason; } }); });
10
Q - ‚parallel’ invocations
Q.all(promises).then(function(results) { results.forEach(function(result) { if (result.state === "fulfilled") { var value = result.value; } else { var reason = result.reason; } }); });
11
Q - wrapping existing solutions (DWR)
function qDwr(dwrFunc, arrayOfParameters) { var deferred = Q.defer(); if (arrayOfParameters === undefined || arrayOfParameters === null) { arrayOfParameters = []; } arrayOfParameters.push(function(data) { deferred.notify(); if (data.faulty) { deferred.reject(data); } else { deferred.resolve(data.data); } }); dwrFunc.apply(this, arrayOfParameters); return deferred.promise; }
12
Q - using existing solutions (DWR)
Q.all([qDwr(Remote.asyncCall), qDwr(Remote.anotherAsyncCall), qDwr(Remote.evenMoreAnotherAsyncCall, [false])]) //Spread results of all invocations .spread(function(firstResult, secondResult, thirdResult) { function render(data, element) { $(element).html($.Mustache.render("template-id", data)); } ! render(firstResult, "first-container"); render(secondResult, "second-container"); render(thirdResult, "container-container"); }).progress(function() { console.log("Notification for each request"); }).catch(function(error) { //One error handler for everything. //Without catch, error will be propagated to browser window.alert(error); }).done();