Commit 5ccaf0c5 authored by Tristan Cavelier's avatar Tristan Cavelier

Merge remote-tracking branch 'remote/cancellable' into cancellable

Conflicts:
	lib/rsvp/all.js
	test/tests/extension_test.js
parents 4118cd40 558ac4dd
...@@ -55,11 +55,16 @@ function promiseAtLeast(expected_count, promises) { ...@@ -55,11 +55,16 @@ function promiseAtLeast(expected_count, promises) {
}; };
} }
function cancelAll(rejectionValue) {
reject(rejectionValue);
canceller();
}
for (var i = 0; i < promises.length; i++) { for (var i = 0; i < promises.length; i++) {
promise = promises[i]; promise = promises[i];
if (promise && typeof promise.then === 'function') { if (promise && typeof promise.then === 'function') {
promise.then(resolver(i), reject, notifier(i)); promise.then(resolver(i), cancelAll, notifier(i));
} else { } else {
resolveAll(i, promise); resolveAll(i, promise);
} }
......
...@@ -83,6 +83,9 @@ var invokeCallback = function(type, promise, callback, event) { ...@@ -83,6 +83,9 @@ var invokeCallback = function(type, promise, callback, event) {
var hasCallback = isFunction(callback), var hasCallback = isFunction(callback),
value, error, succeeded, failed; value, error, succeeded, failed;
if (promise.isFulfilled) { return; }
if (promise.isRejected) { return; }
if (hasCallback) { if (hasCallback) {
try { try {
value = callback(event.detail); value = callback(event.detail);
...@@ -234,6 +237,8 @@ function handleThenable(promise, value) { ...@@ -234,6 +237,8 @@ function handleThenable(promise, value) {
function fulfill(promise, value) { function fulfill(promise, value) {
config.async(function() { config.async(function() {
if (promise.isFulfilled) { return; }
if (promise.isRejected) { return; }
promise.trigger('promise:resolved', { detail: value }); promise.trigger('promise:resolved', { detail: value });
promise.isFulfilled = true; promise.isFulfilled = true;
promise.fulfillmentValue = value; promise.fulfillmentValue = value;
...@@ -242,6 +247,8 @@ function fulfill(promise, value) { ...@@ -242,6 +247,8 @@ function fulfill(promise, value) {
function reject(promise, value) { function reject(promise, value) {
config.async(function() { config.async(function() {
if (promise.isFulfilled) { return; }
if (promise.isRejected) { return; }
promise.trigger('promise:failed', { detail: value }); promise.trigger('promise:failed', { detail: value });
promise.isRejected = true; promise.isRejected = true;
promise.rejectedReason = value; promise.rejectedReason = value;
......
...@@ -23,7 +23,7 @@ var Queue = function() { ...@@ -23,7 +23,7 @@ var Queue = function() {
} }
function canceller() { function canceller() {
for (var i = 0; i < promise_list.length; i++) { for (var i = 0; i < 2; i++) {
promise_list[i].cancel(); promise_list[i].cancel();
} }
} }
......
...@@ -782,6 +782,36 @@ describe("RSVP extensions", function() { ...@@ -782,6 +782,36 @@ describe("RSVP extensions", function() {
}, 20); }, 20);
}); });
specify('cancel the array of promise as soon as rejected', function(done) {
var firstResolver, secondResolver;
var first = new RSVP.Promise(function(resolve, reject) {
firstResolver = { resolve: resolve, reject: reject };
});
var second = new RSVP.Promise(function(resolve, reject) {
secondResolver = { resolve: resolve, reject: reject };
});
setTimeout(function() {
firstResolver.reject("Foo");
}, 0);
setTimeout(function() {
secondResolver.resolve(true);
}, 5000);
var all_promise = RSVP.all([first, second]);
setTimeout(function() {
assert(first.isRejected);
assert.equal(first.rejectedReason, "Foo");
assert(second.isRejected);
assert(second.rejectedReason instanceof RSVP.CancellationError);
done();
}, 20);
});
specify('cancel with non cancellable thenables', function(done) { specify('cancel with non cancellable thenables', function(done) {
var firstResolver, secondResolver; var firstResolver, secondResolver;
...@@ -1026,6 +1056,36 @@ describe("RSVP extensions", function() { ...@@ -1026,6 +1056,36 @@ describe("RSVP extensions", function() {
}, 20); }, 20);
}); });
specify('cancel the array of promise as soon as rejected', function(done) {
var firstResolver, secondResolver;
var first = new RSVP.Promise(function(resolve, reject) {
firstResolver = { resolve: resolve, reject: reject };
});
var second = new RSVP.Promise(function(resolve, reject) {
secondResolver = { resolve: resolve, reject: reject };
});
setTimeout(function() {
firstResolver.reject("Foo");
}, 0);
setTimeout(function() {
secondResolver.resolve(true);
}, 5000);
var all_promise = RSVP.any([first, second]);
setTimeout(function() {
assert(first.isRejected);
assert.equal(first.rejectedReason, "Foo");
assert(second.isRejected);
assert(second.rejectedReason instanceof RSVP.CancellationError);
done();
}, 20);
});
specify('cancel with non cancellable thenables', function(done) { specify('cancel with non cancellable thenables', function(done) {
var firstResolver, secondResolver; var firstResolver, secondResolver;
...@@ -1691,6 +1751,50 @@ describe("`cancel` on promise created by then", function () { ...@@ -1691,6 +1751,50 @@ describe("`cancel` on promise created by then", function () {
assert.equal(typeof promise.cancel, "function"); assert.equal(typeof promise.cancel, "function");
}); });
it('should stop parent fulFillment propagation', function (done) {
var promise = new RSVP.resolve(1),
promise2 = promise.then();
promise2.cancel("Foo");
setTimeout(function() {
assert.equal(promise2.isRejected, true);
assert.equal(promise2.isFulfilled, undefined);
assert(promise2.rejectedReason instanceof RSVP.CancellationError);
done();
}, 20);
});
it('should stop parent rejection propagation', function (done) {
var reject_count = 0,
promise = new RSVP.reject(1),
promise2 = promise.fail(function () {reject_count += 1;});
promise2.cancel("Foo");
setTimeout(function() {
assert.equal(promise2.isRejected, true);
assert.equal(promise2.isFulfilled, undefined);
assert(promise2.rejectedReason instanceof RSVP.CancellationError);
assert.equal(reject_count, 1);
done();
}, 20);
});
it('should not be callable twice', function (done) {
var reject_count = 0,
promise = new RSVP.reject(1),
promise2 = promise.fail(function () {reject_count += 1;});
promise2.cancel("Foo");
promise2.cancel("Bar");
setTimeout(function() {
assert.equal(promise2.isRejected, true);
assert.equal(promise2.isFulfilled, undefined);
assert(promise2.rejectedReason instanceof RSVP.CancellationError);
assert.equal(reject_count, 1);
done();
}, 20);
});
it('should cancel the pending fulfilled promise', function (done) { it('should cancel the pending fulfilled promise', function (done) {
var cancel_called = false, var cancel_called = false,
promise = new RSVP.Promise(function (resolve) {resolve();}), promise = new RSVP.Promise(function (resolve) {resolve();}),
...@@ -2088,13 +2192,12 @@ describe("`RSVP.Queue`", function () { ...@@ -2088,13 +2192,12 @@ describe("`RSVP.Queue`", function () {
assert(promise instanceof RSVP.Promise); assert(promise instanceof RSVP.Promise);
}); });
it('should work without `new`', function(done) { it('should work without `new`', function() {
var promise = RSVP.Queue() var promise = RSVP.Queue()
.push(function() { return 'value'; }); .push(function() { return 'value'; });
promise.then(function(value) { promise.then(function(value) {
assert.equal(value, 'value'); assert.equal(value, 'value');
done();
}); });
}); });
}); });
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment