UNPKG

4.61 kBJavaScriptView Raw
1"use strict";
2module.exports = function(Promise, tryConvertToPromise, NEXT_FILTER) {
3var util = require("./util");
4var CancellationError = Promise.CancellationError;
5var errorObj = util.errorObj;
6var catchFilter = require("./catch_filter")(NEXT_FILTER);
7
8function PassThroughHandlerContext(promise, type, handler) {
9 this.promise = promise;
10 this.type = type;
11 this.handler = handler;
12 this.called = false;
13 this.cancelPromise = null;
14}
15
16PassThroughHandlerContext.prototype.isFinallyHandler = function() {
17 return this.type === 0;
18};
19
20function FinallyHandlerCancelReaction(finallyHandler) {
21 this.finallyHandler = finallyHandler;
22}
23
24FinallyHandlerCancelReaction.prototype._resultCancelled = function() {
25 checkCancel(this.finallyHandler);
26};
27
28function checkCancel(ctx, reason) {
29 if (ctx.cancelPromise != null) {
30 if (arguments.length > 1) {
31 ctx.cancelPromise._reject(reason);
32 } else {
33 ctx.cancelPromise._cancel();
34 }
35 ctx.cancelPromise = null;
36 return true;
37 }
38 return false;
39}
40
41function succeed() {
42 return finallyHandler.call(this, this.promise._target()._settledValue());
43}
44function fail(reason) {
45 if (checkCancel(this, reason)) return;
46 errorObj.e = reason;
47 return errorObj;
48}
49function finallyHandler(reasonOrValue) {
50 var promise = this.promise;
51 var handler = this.handler;
52
53 if (!this.called) {
54 this.called = true;
55 var ret = this.isFinallyHandler()
56 ? handler.call(promise._boundValue())
57 : handler.call(promise._boundValue(), reasonOrValue);
58 if (ret === NEXT_FILTER) {
59 return ret;
60 } else if (ret !== undefined) {
61 promise._setReturnedNonUndefined();
62 var maybePromise = tryConvertToPromise(ret, promise);
63 if (maybePromise instanceof Promise) {
64 if (this.cancelPromise != null) {
65 if (maybePromise._isCancelled()) {
66 var reason =
67 new CancellationError("late cancellation observer");
68 promise._attachExtraTrace(reason);
69 errorObj.e = reason;
70 return errorObj;
71 } else if (maybePromise.isPending()) {
72 maybePromise._attachCancellationCallback(
73 new FinallyHandlerCancelReaction(this));
74 }
75 }
76 return maybePromise._then(
77 succeed, fail, undefined, this, undefined);
78 }
79 }
80 }
81
82 if (promise.isRejected()) {
83 checkCancel(this);
84 errorObj.e = reasonOrValue;
85 return errorObj;
86 } else {
87 checkCancel(this);
88 return reasonOrValue;
89 }
90}
91
92Promise.prototype._passThrough = function(handler, type, success, fail) {
93 if (typeof handler !== "function") return this.then();
94 return this._then(success,
95 fail,
96 undefined,
97 new PassThroughHandlerContext(this, type, handler),
98 undefined);
99};
100
101Promise.prototype.lastly =
102Promise.prototype["finally"] = function (handler) {
103 return this._passThrough(handler,
104 0,
105 finallyHandler,
106 finallyHandler);
107};
108
109
110Promise.prototype.tap = function (handler) {
111 return this._passThrough(handler, 1, finallyHandler);
112};
113
114Promise.prototype.tapCatch = function (handlerOrPredicate) {
115 var len = arguments.length;
116 if(len === 1) {
117 return this._passThrough(handlerOrPredicate,
118 1,
119 undefined,
120 finallyHandler);
121 } else {
122 var catchInstances = new Array(len - 1),
123 j = 0, i;
124 for (i = 0; i < len - 1; ++i) {
125 var item = arguments[i];
126 if (util.isObject(item)) {
127 catchInstances[j++] = item;
128 } else {
129 return Promise.reject(new TypeError(
130 "tapCatch statement predicate: "
131 + "expecting an object but got " + util.classString(item)
132 ));
133 }
134 }
135 catchInstances.length = j;
136 var handler = arguments[i];
137 return this._passThrough(catchFilter(catchInstances, handler, this),
138 1,
139 undefined,
140 finallyHandler);
141 }
142
143};
144
145return PassThroughHandlerContext;
146};