- WinJS Promise Notes 1 - A Study of WinJS Promise
- WinJS Promise Notes 2 - More On WinJS Promise
- WinJS Promise Notes 3 - WinJS Promise Any and Join
- WinJS Promise Notes 4 - Promisable Windows Runtime Component
- WinJS Promise Notes 5 - WinJS Promises Run in Sequence
function addAsync(number1, number2, delayInSeconds) { return new WinJS.Promise(function (c, m, p) { setTimeout(function () { c(number1 + number2); }, delayInSeconds * 1000); }); } function test() { var promise1 = addAsync(1, 1, 3); var promise2 = addAsync(2, 2, 2); var promise3 = addAsync(3, 3, 1); WinJS.Promise.any([promise1, promise2, promise3]).then(function (data) { var key = data.key; // key = 2 var value = data.value; // value is a Promise var realValue = value._value; // realValue = 6 }); }On the other hand, Promise.join function will wait for all Promises in an array to complete before the then function starts. The same size of array holding each Promise's return will be passed to the then function:
function addAsync(number1, number2, delayInSeconds) { return new WinJS.Promise(function (c, m, p) { setTimeout(function () { c(number1 + number2); }, delayInSeconds * 1000); }); } function test() { var promise1 = addAsync(1, 1, 3); var promise2 = addAsync(2, 2, 2); var promise3 = addAsync(3, 3, 1); WinJS.Promise.join([promise1, promise2, promise3]).then(function (data) { var promise1Return = data[0]; // promise1Return = 2 var promise2Return = data[1]; // promise2Return = 4 var promise3Return = data[2]; // promise3Return = 6 }); }What happens if exception occurs inside the Promise? Let's change a little of the test code:
function test() { var promise1 = addAsync(1, 1, 3); var promise2 = addAsync(2, 2, 2).then(function () { throw "promise2 error" }); var promise3 = addAsync(3, 3, 1); WinJS.Promise.any([promise1, promise2, promise3]).done(function () { console.log("Promise.any completed"); }, function (err) { console.log("Promise.any err: " + err); }); WinJS.Promise.join([promise1, promise2, promise3]).done(function () { console.log("Promise.join completed"); }, function (err) { console.log("Promise.join err: " + err); }); }The result is:
Promise.any completed Promise.join err: ,promise2 errorWe can see Promise.any function would complete successfully if any of the Promise object is completed without error. But Promise.join would fail and jump to error handler if any Promise object throws exception. There's a comma "," in error message because like the return data in okay case, the errors are wrapped to an array and mapped to the Promise index, in above case: err[0] is undefined and err[1] is "promise2 error" message.
Reference: the source of Promise.any and Promise.join is defined in base.js from WinJS library:
any: function Promise_any(values) { /// <signature helpKeyword="WinJS.Promise.any"> /// <summary locid="WinJS.Promise.any"> /// Returns a promise that is fulfilled when one of the input promises /// has been fulfilled. /// </summary> /// <param name="values" type="Array" locid="WinJS.Promise.any_p:values"> /// An array that contains promise objects or objects whose property /// values include promise objects. /// </param> /// <returns type="WinJS.Promise" locid="WinJS.Promise.any_returnValue"> /// A promise that on fulfillment yields the value of the input (complete or error). /// </returns> /// </signature> return new Promise( function (complete, error, progress) { var keys = Object.keys(values); var errors = Array.isArray(values) ? [] : {}; if (keys.length === 0) { complete(); } var canceled = 0; keys.forEach(function (key) { Promise.as(values[key]).then( function () { complete({ key: key, value: values[key] }); }, function (e) { if (e instanceof Error && e.name === canceledName) { if ((++canceled) === keys.length) { complete(WinJS.Promise.cancel); } return; } error({ key: key, value: values[key] }); } ); }); }, function () { var keys = Object.keys(values); keys.forEach(function (key) { var promise = Promise.as(values[key]); if (typeof promise.cancel === "function") { promise.cancel(); } }); } ); }, join: function Promise_join(values) { /// <signature helpKeyword="WinJS.Promise.join"> /// <summary locid="WinJS.Promise.join"> /// Creates a promise that is fulfilled when all the values are fulfilled. /// </summary> /// <param name="values" type="Object" locid="WinJS.Promise.join_p:values"> /// An object whose fields contain values, some of which may be promises. /// </param> /// <returns type="WinJS.Promise" locid="WinJS.Promise.join_returnValue"> /// A promise whose value is an object with the same field names as those of the object in the values parameter, where /// each field value is the fulfilled value of a promise. /// </returns> /// </signature> return new Promise( function (complete, error, progress) { var keys = Object.keys(values); var errors = Array.isArray(values) ? [] : {}; var results = Array.isArray(values) ? [] : {}; var undefineds = 0; var pending = keys.length; var argDone = function (key) { if ((--pending) === 0) { var errorCount = Object.keys(errors).length; if (errorCount === 0) { complete(results); } else { var canceledCount = 0; keys.forEach(function (key) { var e = errors[key]; if (e instanceof Error && e.name === canceledName) { canceledCount++; } }); if (canceledCount === errorCount) { complete(WinJS.Promise.cancel); } else { error(errors); } } } else { progress({ Key: key, Done: true }); } }; keys.forEach(function (key) { var value = values[key]; if (value === undefined) { undefineds++; } else { Promise.then(value, function (value) { results[key] = value; argDone(key); }, function (value) { errors[key] = value; argDone(key); } ); } }); pending -= undefineds; if (pending === 0) { complete(results); return; } }, function () { Object.keys(values).forEach(function (key) { var promise = Promise.as(values[key]); if (typeof promise.cancel === "function") { promise.cancel(); } }); } ); }