Skip to content

Commit

Permalink
Fix memory leak
Browse files Browse the repository at this point in the history
Fixes the memory described at
promises-aplus/promises-spec#179
  • Loading branch information
petkaantonov committed Dec 28, 2014
1 parent 3e4bbe3 commit 8c1edaf
Show file tree
Hide file tree
Showing 15 changed files with 445 additions and 269 deletions.
2 changes: 1 addition & 1 deletion src/cancel.js
Expand Up @@ -18,7 +18,7 @@ Promise.prototype._cancel = function (reason) {
ASSERT(promiseToReject.isCancellable()); ASSERT(promiseToReject.isCancellable());
this._unsetCancellable(); this._unsetCancellable();
promiseToReject._attachExtraTrace(reason); promiseToReject._attachExtraTrace(reason);
promiseToReject._rejectUnchecked(reason); promiseToReject._target()._rejectUnchecked(reason);
}; };


Promise.prototype.cancel = function (reason) { Promise.prototype.cancel = function (reason) {
Expand Down
5 changes: 1 addition & 4 deletions src/constants.js
Expand Up @@ -27,7 +27,7 @@ CONSTANT(CALLBACK_PROMISE_OFFSET, 3);
CONSTANT(CALLBACK_RECEIVER_OFFSET, 4); CONSTANT(CALLBACK_RECEIVER_OFFSET, 4);
CONSTANT(CALLBACK_SIZE, 5); CONSTANT(CALLBACK_SIZE, 5);
//Layout for ._bitField //Layout for ._bitField
//QQWF NCTR BPHS UDLL LLLL LLLL LLLL LLLL //QQWF NCTR B[R]HS UDLL LLLL LLLL LLLL LLLL
//Q = isSettlePromisesQueued (Both bits are either on or off to represent //Q = isSettlePromisesQueued (Both bits are either on or off to represent
// 1 bit due to 31-bit integers in 32-bit v8) // 1 bit due to 31-bit integers in 32-bit v8)
//W = isFollowing (The promise that is being followed is not stored explicitly) //W = isFollowing (The promise that is being followed is not stored explicitly)
Expand All @@ -36,8 +36,6 @@ CONSTANT(CALLBACK_SIZE, 5);
//C = isCancellable //C = isCancellable
//T = isFinal (used for .done() implementation) //T = isFinal (used for .done() implementation)
//B = isBound //B = isBound
//P = isProxied (optimization when .then listeners on a promise are
// just respective fate sealers on some other promise)
//H = isRejectionUnhandled //H = isRejectionUnhandled
//S = isCarryingStackTrace //S = isCarryingStackTrace
//U = isUnhanldedRejectionNotified //U = isUnhanldedRejectionNotified
Expand All @@ -52,7 +50,6 @@ CONSTANT(IS_REJECTED, 0x8000000|0);
CONSTANT(IS_CANCELLABLE, 0x4000000|0); CONSTANT(IS_CANCELLABLE, 0x4000000|0);
CONSTANT(IS_FINAL, 0x2000000|0); CONSTANT(IS_FINAL, 0x2000000|0);
CONSTANT(IS_BOUND, 0x800000|0); CONSTANT(IS_BOUND, 0x800000|0);
CONSTANT(IS_PROXIED, 0x400000|0);
CONSTANT(IS_REJECTION_UNHANDLED, 0x200000|0); CONSTANT(IS_REJECTION_UNHANDLED, 0x200000|0);
CONSTANT(IS_CARRYING_STACK_TRACE, 0x100000|0); CONSTANT(IS_CARRYING_STACK_TRACE, 0x100000|0);
CONSTANT(IS_UNHANDLED_REJECTION_NOTIFIED, 0x80000|0); CONSTANT(IS_UNHANDLED_REJECTION_NOTIFIED, 0x80000|0);
Expand Down
2 changes: 2 additions & 0 deletions src/finally.js
Expand Up @@ -43,6 +43,7 @@ function finallyHandler(reasonOrValue) {
if (ret !== undefined) { if (ret !== undefined) {
var maybePromise = tryConvertToPromise(ret, undefined); var maybePromise = tryConvertToPromise(ret, undefined);
if (maybePromise instanceof Promise) { if (maybePromise instanceof Promise) {
maybePromise = maybePromise._target();
return promisedFinally(maybePromise, reasonOrValue, return promisedFinally(maybePromise, reasonOrValue,
promise.isFulfilled()); promise.isFulfilled());
} }
Expand Down Expand Up @@ -70,6 +71,7 @@ function tapHandler(value) {
if (ret !== undefined) { if (ret !== undefined) {
var maybePromise = tryConvertToPromise(ret, undefined); var maybePromise = tryConvertToPromise(ret, undefined);
if (maybePromise instanceof Promise) { if (maybePromise instanceof Promise) {
maybePromise = maybePromise._target();
return promisedFinally(maybePromise, value, true); return promisedFinally(maybePromise, value, true);
} }
} }
Expand Down
9 changes: 5 additions & 4 deletions src/join.js
Expand Up @@ -75,14 +75,15 @@ Promise.join = function () {
for (var i = 0; i < last; ++i) { for (var i = 0; i < last; ++i) {
var maybePromise = tryConvertToPromise(arguments[i], undefined); var maybePromise = tryConvertToPromise(arguments[i], undefined);
if (maybePromise instanceof Promise) { if (maybePromise instanceof Promise) {
if (maybePromise.isPending()) { maybePromise = maybePromise._target();
if (maybePromise._isPending()) {
maybePromise._then(callbacks[i], reject, maybePromise._then(callbacks[i], reject,
undefined, ret, holder); undefined, ret, holder);
} else if (maybePromise.isFulfilled()) { } else if (maybePromise._isFulfilled()) {
callbacks[i].call(ret, callbacks[i].call(ret,
maybePromise._settledValue, holder); maybePromise._value(), holder);
} else { } else {
ret._reject(maybePromise._settledValue); ret._reject(maybePromise._reason());
maybePromise._unsetRejectionIsUnhandled(); maybePromise._unsetRejectionIsUnhandled();
} }
} else { } else {
Expand Down
9 changes: 5 additions & 4 deletions src/map.js
Expand Up @@ -67,15 +67,16 @@ MappingPromiseArray.prototype._promiseFulfilled = function (value, index) {
// anymore), the marker PENDING is put at that index // anymore), the marker PENDING is put at that index
var maybePromise = tryConvertToPromise(ret, this._promise); var maybePromise = tryConvertToPromise(ret, this._promise);
if (maybePromise instanceof Promise) { if (maybePromise instanceof Promise) {
if (maybePromise.isPending()) { maybePromise = maybePromise._target();
if (maybePromise._isPending()) {
if (limit >= 1) this._inFlight++; if (limit >= 1) this._inFlight++;
values[index] = PENDING; values[index] = PENDING;
return maybePromise._proxyPromiseArray(this, index); return maybePromise._proxyPromiseArray(this, index);
} else if (maybePromise.isFulfilled()) { } else if (maybePromise._isFulfilled()) {
ret = maybePromise._settledValue; ret = maybePromise._value();
} else { } else {
maybePromise._unsetRejectionIsUnhandled(); maybePromise._unsetRejectionIsUnhandled();
return this._reject(maybePromise._settledValue); return this._reject(maybePromise._reason());
} }
} }
values[index] = ret; values[index] = ret;
Expand Down
6 changes: 2 additions & 4 deletions src/progress.js
Expand Up @@ -13,7 +13,7 @@ Promise.prototype.progressed = function (handler) {


Promise.prototype._progress = function (progressValue) { Promise.prototype._progress = function (progressValue) {
if (this._isFollowingOrFulfilledOrRejected()) return; if (this._isFollowingOrFulfilledOrRejected()) return;
this._progressUnchecked(progressValue); this._target()._progressUnchecked(progressValue);


}; };


Expand Down Expand Up @@ -67,7 +67,7 @@ Promise.prototype._doProgressWith = function (progression) {




Promise.prototype._progressUnchecked = function (progressValue) { Promise.prototype._progressUnchecked = function (progressValue) {
if (!this.isPending()) return; ASSERT(!this._isFollowingOrFulfilledOrRejected());
var len = this._length(); var len = this._length();
var progress = this._progress; var progress = this._progress;
for (var i = 0; i < len; i++) { for (var i = 0; i < len; i++) {
Expand All @@ -79,8 +79,6 @@ Promise.prototype._progressUnchecked = function (progressValue) {
var receiver = this._receiverAt(i); var receiver = this._receiverAt(i);
if (typeof handler === "function") { if (typeof handler === "function") {
handler.call(receiver, progressValue, promise); handler.call(receiver, progressValue, promise);
} else if (receiver instanceof Promise && receiver._isProxied()) {
receiver._progressUnchecked(progressValue);
} else if (receiver instanceof PromiseArray && } else if (receiver instanceof PromiseArray &&
!receiver._isResolved()) { !receiver._isResolved()) {
receiver._promiseProgressed(progressValue, promise); receiver._promiseProgressed(progressValue, promise);
Expand Down

0 comments on commit 8c1edaf

Please sign in to comment.