101 lines
2.9 KiB
JavaScript
101 lines
2.9 KiB
JavaScript
|
"use strict";
|
||
|
module.exports = function(Promise, tryConvertToPromise) {
|
||
|
var util = require("./util");
|
||
|
var CancellationError = Promise.CancellationError;
|
||
|
var errorObj = util.errorObj;
|
||
|
|
||
|
function FinallyHandlerCancelReaction(finallyHandler) {
|
||
|
this.finallyHandler = finallyHandler;
|
||
|
}
|
||
|
|
||
|
FinallyHandlerCancelReaction.prototype._resultCancelled = function() {
|
||
|
checkCancel(this.finallyHandler);
|
||
|
};
|
||
|
|
||
|
function checkCancel(ctx, reason) {
|
||
|
if (ctx.cancelPromise != null) {
|
||
|
if (arguments.length > 1) {
|
||
|
ctx.cancelPromise._reject(reason);
|
||
|
} else {
|
||
|
ctx.cancelPromise._cancel();
|
||
|
}
|
||
|
ctx.cancelPromise = null;
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
function succeed() {
|
||
|
return finallyHandler.call(this, this.promise._target()._settledValue());
|
||
|
}
|
||
|
function fail(reason) {
|
||
|
if (checkCancel(this, reason)) return;
|
||
|
errorObj.e = reason;
|
||
|
return errorObj;
|
||
|
}
|
||
|
function finallyHandler(reasonOrValue) {
|
||
|
var promise = this.promise;
|
||
|
var handler = this.handler;
|
||
|
|
||
|
if (!this.called) {
|
||
|
this.called = true;
|
||
|
var ret = this.type === 0
|
||
|
? handler.call(promise._boundValue())
|
||
|
: handler.call(promise._boundValue(), reasonOrValue);
|
||
|
if (ret !== undefined) {
|
||
|
var maybePromise = tryConvertToPromise(ret, promise);
|
||
|
if (maybePromise instanceof Promise) {
|
||
|
if (this.cancelPromise != null) {
|
||
|
if (maybePromise.isCancelled()) {
|
||
|
var reason =
|
||
|
new CancellationError("late cancellation observer");
|
||
|
promise._attachExtraTrace(reason);
|
||
|
errorObj.e = reason;
|
||
|
return errorObj;
|
||
|
} else if (maybePromise.isPending()) {
|
||
|
maybePromise._attachCancellationCallback(
|
||
|
new FinallyHandlerCancelReaction(this));
|
||
|
}
|
||
|
}
|
||
|
return maybePromise._then(
|
||
|
succeed, fail, undefined, this, undefined);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (promise.isRejected()) {
|
||
|
checkCancel(this);
|
||
|
errorObj.e = reasonOrValue;
|
||
|
return errorObj;
|
||
|
} else {
|
||
|
checkCancel(this);
|
||
|
return reasonOrValue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Promise.prototype._passThrough = function(handler, type, success, fail) {
|
||
|
if (typeof handler !== "function") return this.then();
|
||
|
return this._then(success, fail, undefined, {
|
||
|
promise: this,
|
||
|
handler: handler,
|
||
|
called: false,
|
||
|
cancelPromise: null,
|
||
|
type: type
|
||
|
}, undefined);
|
||
|
};
|
||
|
|
||
|
Promise.prototype.lastly =
|
||
|
Promise.prototype["finally"] = function (handler) {
|
||
|
return this._passThrough(handler,
|
||
|
0,
|
||
|
finallyHandler,
|
||
|
finallyHandler);
|
||
|
};
|
||
|
|
||
|
Promise.prototype.tap = function (handler) {
|
||
|
return this._passThrough(handler, 1, finallyHandler);
|
||
|
};
|
||
|
|
||
|
return finallyHandler;
|
||
|
};
|