You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
111 lines
3.3 KiB
111 lines
3.3 KiB
"use strict";
|
|
module.exports = function(Promise, tryConvertToPromise) {
|
|
var util = require("./util");
|
|
var CancellationError = Promise.CancellationError;
|
|
var errorObj = util.errorObj;
|
|
|
|
function PassThroughHandlerContext(promise, type, handler) {
|
|
this.promise = promise;
|
|
this.type = type;
|
|
this.handler = handler;
|
|
this.called = false;
|
|
this.cancelPromise = null;
|
|
}
|
|
|
|
PassThroughHandlerContext.prototype.isFinallyHandler = function() {
|
|
return this.type === 0;
|
|
};
|
|
|
|
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.isFinallyHandler()
|
|
? handler.call(promise._boundValue())
|
|
: handler.call(promise._boundValue(), reasonOrValue);
|
|
if (ret !== undefined) {
|
|
promise._setReturnedNonUndefined();
|
|
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,
|
|
new PassThroughHandlerContext(this, type, handler),
|
|
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 PassThroughHandlerContext;
|
|
};
|
|
|