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