• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"use strict";
2module.exports = function(Promise, PromiseArray, apiRejection, debug) {
3var util = require("./util");
4var tryCatch = util.tryCatch;
5var errorObj = util.errorObj;
6var async = Promise._async;
7
8Promise.prototype["break"] = Promise.prototype.cancel = function() {
9    if (!debug.cancellation()) return this._warn("cancellation is disabled");
10
11    var promise = this;
12    var child = promise;
13    while (promise._isCancellable()) {
14        if (!promise._cancelBy(child)) {
15            if (child._isFollowing()) {
16                child._followee().cancel();
17            } else {
18                child._cancelBranched();
19            }
20            break;
21        }
22
23        var parent = promise._cancellationParent;
24        if (parent == null || !parent._isCancellable()) {
25            if (promise._isFollowing()) {
26                promise._followee().cancel();
27            } else {
28                promise._cancelBranched();
29            }
30            break;
31        } else {
32            if (promise._isFollowing()) promise._followee().cancel();
33            promise._setWillBeCancelled();
34            child = promise;
35            promise = parent;
36        }
37    }
38};
39
40Promise.prototype._branchHasCancelled = function() {
41    this._branchesRemainingToCancel--;
42};
43
44Promise.prototype._enoughBranchesHaveCancelled = function() {
45    return this._branchesRemainingToCancel === undefined ||
46           this._branchesRemainingToCancel <= 0;
47};
48
49Promise.prototype._cancelBy = function(canceller) {
50    if (canceller === this) {
51        this._branchesRemainingToCancel = 0;
52        this._invokeOnCancel();
53        return true;
54    } else {
55        this._branchHasCancelled();
56        if (this._enoughBranchesHaveCancelled()) {
57            this._invokeOnCancel();
58            return true;
59        }
60    }
61    return false;
62};
63
64Promise.prototype._cancelBranched = function() {
65    if (this._enoughBranchesHaveCancelled()) {
66        this._cancel();
67    }
68};
69
70Promise.prototype._cancel = function() {
71    if (!this._isCancellable()) return;
72    this._setCancelled();
73    async.invoke(this._cancelPromises, this, undefined);
74};
75
76Promise.prototype._cancelPromises = function() {
77    if (this._length() > 0) this._settlePromises();
78};
79
80Promise.prototype._unsetOnCancel = function() {
81    this._onCancelField = undefined;
82};
83
84Promise.prototype._isCancellable = function() {
85    return this.isPending() && !this._isCancelled();
86};
87
88Promise.prototype.isCancellable = function() {
89    return this.isPending() && !this.isCancelled();
90};
91
92Promise.prototype._doInvokeOnCancel = function(onCancelCallback, internalOnly) {
93    if (util.isArray(onCancelCallback)) {
94        for (var i = 0; i < onCancelCallback.length; ++i) {
95            this._doInvokeOnCancel(onCancelCallback[i], internalOnly);
96        }
97    } else if (onCancelCallback !== undefined) {
98        if (typeof onCancelCallback === "function") {
99            if (!internalOnly) {
100                var e = tryCatch(onCancelCallback).call(this._boundValue());
101                if (e === errorObj) {
102                    this._attachExtraTrace(e.e);
103                    async.throwLater(e.e);
104                }
105            }
106        } else {
107            onCancelCallback._resultCancelled(this);
108        }
109    }
110};
111
112Promise.prototype._invokeOnCancel = function() {
113    var onCancelCallback = this._onCancel();
114    this._unsetOnCancel();
115    async.invoke(this._doInvokeOnCancel, this, onCancelCallback);
116};
117
118Promise.prototype._invokeInternalOnCancel = function() {
119    if (this._isCancellable()) {
120        this._doInvokeOnCancel(this._onCancel(), true);
121        this._unsetOnCancel();
122    }
123};
124
125Promise.prototype._resultCancelled = function() {
126    this.cancel();
127};
128
129};
130