Skip to content

Commit

Permalink
The return of Promise.cancel() with some additional tests & docs
Browse files Browse the repository at this point in the history
  • Loading branch information
felixge authored and ry committed Oct 29, 2009
1 parent 7b2fdc0 commit 659954d
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 1 deletion.
17 changes: 16 additions & 1 deletion doc/api.txt
Expand Up @@ -215,6 +215,7 @@ emit anymore events.
| Event | Parameters | Notes
| +"success"+ | (depends) |
| +"error"+ | (depends) |
| +"cancel"+ | (depends) |
|=========================================================

+promise.addCallback(listener)+ ::
Expand All @@ -223,6 +224,9 @@ Adds a listener for the +"success"+ event. Returns the same promise object.
+promise.addErrback(listener)+ ::
Adds a listener for the +"error"+ event. Returns the same promise object.

+promise.addCancelback(listener)+ ::
Adds a listener for the +"cancel"+ event. Returns the same promise object.

+promise.emitSuccess(arg1, arg2, ...)+ ::
If you created the promise (by doing +new node.Promise()+) then call
+emitSuccess+ to emit the +"success"+ event with the given arguments.
Expand All @@ -233,10 +237,21 @@ the moment due to a bug; use +emitSuccess+ instead.)
+promise.emitError(arg1, arg2, ...)+ ::
Emits the +"error"+ event.

+promise.emitCancel(arg1, arg2, ...)+ ::
Emits the +"cancel"+ event. You may still get a +"success"+ or +"error"+
callback if the promise giver does not handle the cancel event. Use
+promise.cancel()+ to ignore any later events.

+promise.cancel()+ ::
Clears all +"success"+ and +"error"+ event listeners from the promise, then
emits the +"cancel"+ event. Whether or not the promise is actually canceled
or not depends on the promise giver. This also clears Promise.timeout() if one
was set.

+promise.timeout(timeout = undefined)+ ::
If the +timeout+ parameter is provided, the promise will emit an +"error"+
event after the given amount of millseconds. The timeout is canceled by any
+"success"+ or +"error"+ event being emitted by the Promise.
+"success"+, +"error"+ or +"cancel"+ event being emitted by the Promise.
+
To tell apart a timeout from a regular "error" event, use the following test:
+
Expand Down
33 changes: 33 additions & 0 deletions src/events.js
Expand Up @@ -30,14 +30,42 @@ node.Promise.prototype.timeout = function(timeout) {
clearTimeout(this._timer);
}

var promiseComplete = false;
var onComplete = function() {
promiseComplete = true;
};

this
.addCallback(onComplete)
.addCancelback(onComplete)
.addErrback(onComplete);

var self = this
this._timer = setTimeout(function() {
if (promiseComplete) {
return;
}

self.emitError(new Error('timeout'));
}, this._timeoutDuration);

return this;
};

node.Promise.prototype.cancel = function() {
this._events['success'] = [];
this._events['error'] = [];

this.emitCancel();
};

node.Promise.prototype.emitCancel = function() {
var args = Array.prototype.slice.call(arguments);
args.unshift('cancel');

this.emit.apply(this, args);
};

node.Promise.prototype.addCallback = function (listener) {
this.addListener("success", listener);
return this;
Expand All @@ -48,6 +76,11 @@ node.Promise.prototype.addErrback = function (listener) {
return this;
};

node.Promise.prototype.addCancelback = function (listener) {
this.addListener("cancel", listener);
return this;
};

node.Promise.prototype.wait = function () {
var ret;
var had_error = false;
Expand Down
49 changes: 49 additions & 0 deletions test/mjsunit/test-promise-timeout.js
Expand Up @@ -29,6 +29,55 @@ try {
timeouts++;
}

var successPromise = new node.Promise();
successPromise.timeout(500);
setTimeout(function() {
successPromise.emitSuccess();
}, 250);

successPromise.addErrback(function() {
assertUnreachable('addErrback should not fire if there is no timeout');
});

var errorPromise = new node.Promise();
errorPromise.timeout(500);
setTimeout(function() {
errorPromise.emitError(new Error('intentional'));
}, 250);

errorPromise.addErrback(function(e) {
assertInstanceof(e, Error);
assertEquals('intentional', e.message);
});

var cancelPromise = new node.Promise();
cancelPromise.timeout(500);
setTimeout(function() {
cancelPromise.cancel();
}, 250);

setTimeout(function() {
cancelPromise.emitSuccess('should be ignored');
}, 400);

cancelPromise.addCallback(function(e) {
assertUnreachable('addCallback should not fire if the promise is canceled');
});

cancelPromise.addErrback(function(e) {
assertUnreachable('addErrback should not fire if the promise is canceled');
});

var cancelTimeoutPromise = new node.Promise();
cancelTimeoutPromise.timeout(500);
setTimeout(function() {
cancelPromise.emitCancel();
}, 250);

cancelPromise.addErrback(function(e) {
assertUnreachable('addErrback should not fire after a cancel event');
});

process.addListener('exit', function() {
assertEquals(2, timeouts);
});

0 comments on commit 659954d

Please sign in to comment.