promise.prototype.finally
Advanced tools
Comparing version 2.0.1 to 3.0.0
@@ -0,1 +1,9 @@ | ||
3.0.0 / 2017-07-25 | ||
================= | ||
* [Breaking] update implementation to follow the new spec (#9) | ||
* [Deps] update `es-abstract` | ||
* [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `es6-shim`, `nsp`, `safe-publish-latest`, `tape` | ||
* [Tests] up to `node` `v8.1`, `v7.10`, `v6.11`, `v4.8`; improve matrix | ||
* [Tests] fix 0.10; remove 0.8 | ||
2.0.1 / 2016-09-27 | ||
@@ -2,0 +10,0 @@ ================= |
@@ -10,5 +10,5 @@ 'use strict'; | ||
var getPromise = function getPromise(C, handler) { | ||
var promiseResolve = function PromiseResolve(C, value) { | ||
return new C(function (resolve) { | ||
resolve(handler()); | ||
resolve(value); | ||
}); | ||
@@ -19,25 +19,45 @@ }; | ||
var then = bind.call(Function.call, Promise.prototype.then); | ||
var createThenFinally = function CreateThenFinally(C, onFinally) { | ||
return function (value) { | ||
var result = onFinally(); | ||
var promise = promiseResolve(C, result); | ||
var valueThunk = function () { | ||
return value; | ||
}; | ||
return promise.then(valueThunk); | ||
}; | ||
}; | ||
var createCatchFinally = function CreateCatchFinally(C, onFinally) { | ||
return function (reason) { | ||
var result = onFinally(); | ||
var promise = promiseResolve(C, result); | ||
var thrower = function () { | ||
throw reason; | ||
}; | ||
return promise.then(thrower); | ||
}; | ||
}; | ||
var then = bind.call(Function.call, OriginalPromise.prototype.then); | ||
var promiseFinally = function finally_(onFinally) { | ||
/* eslint no-invalid-this: 0 */ | ||
var handler = typeof onFinally === 'function' ? onFinally : function () {}; | ||
var C; | ||
var newPromise = then( | ||
this, // throw if IsPromise(this) is false | ||
function (x) { | ||
return then(getPromise(C, handler), function () { | ||
return x; | ||
}); | ||
}, | ||
function (e) { | ||
return then(getPromise(C, handler), function () { | ||
throw e; | ||
}); | ||
} | ||
); | ||
C = ES.SpeciesConstructor(this, OriginalPromise); // may throw | ||
return newPromise; | ||
var promise = this; | ||
then(promise); // throw if IsPromise(this) is false | ||
var C = ES.SpeciesConstructor(promise, OriginalPromise); // may throw | ||
var thenFinally = onFinally; | ||
var catchFinally = onFinally; | ||
if (ES.IsCallable(onFinally)) { | ||
thenFinally = createThenFinally(C, onFinally); | ||
catchFinally = createCatchFinally(C, onFinally); | ||
} | ||
return promise.then(thenFinally, catchFinally); | ||
}; | ||
if (Object.getOwnPropertyDescriptor) { | ||
@@ -44,0 +64,0 @@ var descriptor = Object.getOwnPropertyDescriptor(promiseFinally, 'name'); |
{ | ||
"name": "promise.prototype.finally", | ||
"version": "2.0.1", | ||
"version": "3.0.0", | ||
"author": "Jordan Harband", | ||
@@ -52,3 +52,3 @@ "contributors": [ | ||
"define-properties": "^1.1.2", | ||
"es-abstract": "^1.6.1", | ||
"es-abstract": "^1.7.0", | ||
"function-bind": "^1.1.0" | ||
@@ -58,9 +58,9 @@ }, | ||
"@es-shims/api": "^1.2.0", | ||
"@ljharb/eslint-config": "^8.0.0", | ||
"@ljharb/eslint-config": "^12.2.0", | ||
"covert": "^1.1.0", | ||
"es6-shim": "^0.35.1", | ||
"eslint": "^3.6.1", | ||
"nsp": "^2.6.1", | ||
"tape": "^4.6.0", | ||
"safe-publish-latest": "^1.1.0" | ||
"es6-shim": "^0.35.3", | ||
"eslint": "^4.3.0", | ||
"nsp": "^2.6.3", | ||
"safe-publish-latest": "^1.1.1", | ||
"tape": "^4.7.0" | ||
}, | ||
@@ -67,0 +67,0 @@ "testling": { |
@@ -5,3 +5,11 @@ 'use strict'; | ||
// var hasSymbols = typeof Symbol === 'function' && typeof Symbol.iterator === 'symbol'; | ||
var assertArray = function (t, value, length, assertType) { | ||
t.ok(Array.isArray(value), 'value is an array'); | ||
t.equal(value.length, length, 'length is ' + length); | ||
if (typeof assertType === 'function') { | ||
for (var i = 0; i < value.length; i += 1) { | ||
assertType(value[i]); | ||
} | ||
} | ||
}; | ||
@@ -56,3 +64,3 @@ module.exports = function (promiseFinally, t) { | ||
// eslint-disable-next-line no-new-func | ||
return Function('return class Subclass extends Promise {};')(); | ||
return Function('class Subclass extends Promise { constructor(...args) { super(...args); this.thenArgs = []; } then(...args) { Subclass.thenArgs.push(args); this.thenArgs.push(args); return super.then(...args); } } Subclass.thenArgs = []; return Subclass;')(); | ||
} catch (e) { /**/ } | ||
@@ -90,2 +98,105 @@ | ||
}); | ||
st.test('invokes the subclass’ then', function (s2t) { | ||
Subclass.thenArgs.length = 0; | ||
var original = Subclass.resolve(); | ||
promiseFinally(original, function () {}); | ||
assertArray(s2t, original.thenArgs, 1); | ||
assertArray(s2t, Subclass.thenArgs, 1); | ||
s2t.end(); | ||
}); | ||
st.test('passes the original onFinally when not a function', function (s2t) { | ||
Subclass.thenArgs.length = 0; | ||
var original = Subclass.resolve(); | ||
var sentinel = {}; | ||
promiseFinally(original, sentinel); | ||
assertArray(s2t, original.thenArgs, 1, Array.isArray); | ||
assertArray(s2t, Subclass.thenArgs, 1, Array.isArray); | ||
assertArray(s2t, original.thenArgs[0], 2, function (x) { s2t.equal(x, sentinel); }); | ||
s2t.end(); | ||
}); | ||
st.test('when onFinally is a function, passes thenFinally/catchFinally', function (s2t) { | ||
Subclass.thenArgs.length = 0; | ||
var sentinel = {}; | ||
var original = Subclass.resolve(sentinel); | ||
var onFinallyArgs = []; | ||
var onFinally = function onFinallyHandler() { | ||
onFinallyArgs.push(Array.prototype.slice.call(arguments)); | ||
return 42; | ||
}; | ||
var promise = promiseFinally(original, onFinally); | ||
assertArray(s2t, original.thenArgs, 1, Array.isArray); | ||
assertArray(s2t, Subclass.thenArgs, 1, Array.isArray); | ||
var thenArgs = original.thenArgs[0]; | ||
assertArray(s2t, thenArgs, 2, function (x) { s2t.equal(typeof x, 'function'); }); | ||
s2t.deepEqual(onFinallyArgs, [], 'onFinally not yet called'); | ||
s2t.test('thenFinally works as expected', function (s3t) { | ||
onFinallyArgs.length = 0; | ||
s3t.plan(6); | ||
assertArray(s3t, Subclass.thenArgs, 1); | ||
promise.then(function (x) { | ||
s3t.equal(x, sentinel, 'original resolution value provided'); | ||
s3t.deepEqual(onFinallyArgs, [[]], 'onFinally called once with no args'); | ||
assertArray(s3t, Subclass.thenArgs, 9); | ||
s3t.end(); | ||
})['catch'](s3t.fail); | ||
}); | ||
s2t.test('catchFinally works as expected', function (s3t) { | ||
onFinallyArgs.length = 0; | ||
s3t.plan(17); | ||
var thrown = { toString: function () { return 'thrown object'; } }; | ||
var onFinallyRejects = function onFinallyThrower() { | ||
onFinally.apply(undefined, arguments); | ||
throw thrown; | ||
}; | ||
Subclass.thenArgs.length = 0; | ||
var rejectedPromise = promiseFinally(original, onFinallyRejects); | ||
assertArray(s3t, Subclass.thenArgs, 1); | ||
var rejectedPromiseCatch = function (e) { | ||
s3t.equal(e, thrown, 'original rejection value provided'); | ||
s3t.deepEqual(onFinallyArgs, [[]], 'onFinally called once with no args'); | ||
assertArray(s3t, Subclass.thenArgs, 3); | ||
// 1) initial call with thenFinally/catchFinally | ||
// 2) rejectedPromise.then call | ||
// 3) rejectedPromise.then -> onFinally call | ||
assertArray(s3t, Subclass.thenArgs[0], 2, function (x) { s3t.equal(typeof x, 'function'); }); | ||
assertArray(s3t, Subclass.thenArgs[1], 2); | ||
s3t.deepEqual(Subclass.thenArgs[1], [s3t.fail, rejectedPromiseCatch], 'rejectedPromise.then call args'); | ||
assertArray(s3t, Subclass.thenArgs[2], 2); | ||
s3t.equal(Subclass.thenArgs[2][0], undefined, 'final .then call gets no onFulfill'); | ||
s3t.equal(typeof Subclass.thenArgs[2][1], 'function', 'final .then call gets an onReject'); | ||
s3t.end(); | ||
}; | ||
rejectedPromise.then(s3t.fail, rejectedPromiseCatch)['catch'](s3t.fail); | ||
}); | ||
s2t.end(); | ||
}); | ||
}); | ||
@@ -92,0 +203,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
26713
290
Updatedes-abstract@^1.7.0