diff --git a/promise/polyfill.js b/promise/polyfill.js index 4d990dcd..68cd60e1 100644 --- a/promise/polyfill.js +++ b/promise/polyfill.js @@ -61,6 +61,20 @@ PromisePolyfill.prototype.then = function(onFulfilled, onRejection) { PromisePolyfill.prototype.catch = function(onRejection) { return this.then(null, onRejection) } +PromisePolyfill.prototype.finally = function(callback) { + return this.then( + function(value) { + return PromisePolyfill.resolve(callback()).then(function() { + return value + }) + }, + function(reason) { + return PromisePolyfill.resolve(callback()).then(function() { + return PromisePolyfill.reject(reason); + }) + } + ) +} PromisePolyfill.resolve = function(value) { if (value instanceof PromisePolyfill) return value return new PromisePolyfill(function(resolve) {resolve(value)}) diff --git a/promise/promise.js b/promise/promise.js index 1f19bc33..7c6a2d11 100644 --- a/promise/promise.js +++ b/promise/promise.js @@ -3,10 +3,18 @@ var PromisePolyfill = require("./polyfill") if (typeof window !== "undefined") { - if (typeof window.Promise === "undefined") window.Promise = PromisePolyfill + if (typeof window.Promise === "undefined") { + window.Promise = PromisePolyfill + } else if (!window.Promise.prototype.finally) { + window.Promise.prototype.finally = PromisePolyfill.prototype.finally + } module.exports = window.Promise } else if (typeof global !== "undefined") { - if (typeof global.Promise === "undefined") global.Promise = PromisePolyfill + if (typeof global.Promise === "undefined") { + global.Promise = PromisePolyfill + } else if (!global.Promise.prototype.finally) { + global.Promise.prototype.finally = PromisePolyfill.prototype.finally + } module.exports = global.Promise } else { module.exports = PromisePolyfill diff --git a/promise/tests/test-promise.js b/promise/tests/test-promise.js index 2905d694..7dcc21f6 100644 --- a/promise/tests/test-promise.js +++ b/promise/tests/test-promise.js @@ -15,6 +15,7 @@ o.spec("promise", function() { o("constructor has correct methods", function() { o(typeof Promise.prototype.then).equals("function") o(typeof Promise.prototype.catch).equals("function") + o(typeof Promise.prototype.finally).equals("function") o(typeof Promise.resolve).equals("function") o(typeof Promise.reject).equals("function") o(typeof Promise.race).equals("function") @@ -53,6 +54,78 @@ o.spec("promise", function() { o(value).equals(1) }).then(done) }) + o("finally lets a fulfilled value pass though", function(done) { + var promise = Promise.resolve(1) + var spy = o.spy(function(){return 2}) + + promise.finally(spy).then(function(value){ + o(value).equals(1) + o(spy.callCount).equals(1) + o(spy.args.length).equals(0) + o(spy.this).equals(undefined) + done() + }) + }) + o("finally lets a rejected reason pass though", function(done) { + var promise = Promise.reject(1) + var spy = o.spy(function(){return 2}) + + promise.finally(spy).catch(function(reason){ + o(reason).equals(1) + o(spy.callCount).equals(1) + o(spy.args.length).equals(0) + o(spy.this).equals(undefined) + done() + }) + }) + o("finally overrrides a fulfilled value when it throws", function(done) { + var promise = Promise.resolve(1) + var spy = o.spy(function(){throw 2}) + + promise.finally(spy).catch(function(reason){ + o(reason).equals(2) + o(spy.callCount).equals(1) + o(spy.args.length).equals(0) + o(spy.this).equals(undefined) + done() + }) + }) + o("finally overrrides a fulfilled value when it returns a rejected Promise", function(done) { + var promise = Promise.resolve(1) + var spy = o.spy(function(){return Promise.reject(2)}) + + promise.finally(spy).catch(function(reason){ + o(reason).equals(2) + o(spy.callCount).equals(1) + o(spy.args.length).equals(0) + o(spy.this).equals(undefined) + done() + }) + }) + o("finally overrrides a rejected reason when it throws", function(done) { + var promise = Promise.reject(1) + var spy = o.spy(function(){throw 2}) + + promise.finally(spy).catch(function(reason){ + o(reason).equals(2) + o(spy.callCount).equals(1) + o(spy.args.length).equals(0) + o(spy.this).equals(undefined) + done() + }) + }) + o("finally overrrides a rejected reason when it returns a rejected Promise", function(done) { + var promise = Promise.reject(1) + var spy = o.spy(function(){return Promise.reject(2)}) + + promise.finally(spy).catch(function(reason){ + o(reason).equals(2) + o(spy.callCount).equals(1) + o(spy.args.length).equals(0) + o(spy.this).equals(undefined) + done() + }) + }) }) o.spec("resolve", function() { o("resolves once", function(done) {