Commit 595f1186 authored by Romain Courteaud's avatar Romain Courteaud

Make RSVP.hash cancellable

Cancel all subpromises as soon as cancelled.
parent cde40f5c
import { defer } from "./defer";
import { Promise } from "./promise";
function size(object) {
var s = 0;
......@@ -11,38 +11,61 @@ function size(object) {
}
function hash(promises) {
var results = {}, deferred = defer(), remaining = size(promises);
if (remaining === 0) {
deferred.resolve({});
function canceller() {
var promise,
key;
for (key in promises) {
if (promises.hasOwnProperty(key)) {
promise = promises[key];
if (promise && typeof promise.then === 'function' &&
typeof promise.cancel === 'function') {
promise.cancel();
}
}
}
}
var resolver = function(prop) {
return function(value) {
resolveAll(prop, value);
};
};
return new Promise(function(resolve, reject) {
var results = {}, remaining = size(promises),
promise;
var resolveAll = function(prop, value) {
results[prop] = value;
if (--remaining === 0) {
deferred.resolve(results);
if (remaining === 0) {
resolve(results);
}
};
var rejectAll = function(error) {
deferred.reject(error);
};
function resolver(key) {
return function(value) {
resolveAll(key, value);
};
}
for (var prop in promises) {
if (promises[prop] && typeof promises[prop].then === 'function') {
promises[prop].then(resolver(prop), rejectAll);
} else {
resolveAll(prop, promises[prop]);
function resolveAll(key, value) {
results[key] = value;
if (--remaining === 0) {
resolve(results);
}
}
}
return deferred.promise;
function cancelAll(rejectionValue) {
reject(rejectionValue);
canceller();
}
for (var prop in promises) {
promise = promises[prop];
if (promise && typeof promise.then === 'function') {
promise.then(resolver(prop), cancelAll);
} else {
resolveAll(prop, promise);
}
}
}, canceller
);
}
export { hash };
......@@ -564,6 +564,102 @@ describe("RSVP extensions", function() {
});
});
specify('cancel the array of promise as soon as cancelled', 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({});
}, 0);
setTimeout(function() {
secondResolver.resolve(true);
}, 5000);
var all_promise = RSVP.hash({one: "nonPromiseValue", two: first, three: second});
all_promise.cancel();
setTimeout(function() {
assert(first.isRejected);
assert(first.rejectedReason instanceof RSVP.CancellationError);
assert(second.isRejected);
assert(second.rejectedReason instanceof RSVP.CancellationError);
done();
}, 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.hash({one: "nonPromiseValue", two: first, three: 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) {
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({});
}, 0);
setTimeout(function() {
secondResolver.resolve(true);
}, 5000);
var all_promise = RSVP.hash({one: {"then": function () {
return;
}}, two: first, three: second});
all_promise.cancel();
setTimeout(function() {
assert(first.isRejected);
assert(first.rejectedReason instanceof RSVP.CancellationError);
assert(second.isRejected);
assert(second.rejectedReason instanceof RSVP.CancellationError);
done();
}, 20);
});
});
describe("RSVP.all", function() {
......
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