Commit 46330d04 authored by Romain Courteaud's avatar Romain Courteaud

Queue: add a thenable argument to resolve with a Queue

parent 29822afe
...@@ -12,7 +12,7 @@ function ResolvedQueueError(message) { ...@@ -12,7 +12,7 @@ function ResolvedQueueError(message) {
ResolvedQueueError.prototype = new Error(); ResolvedQueueError.prototype = new Error();
ResolvedQueueError.prototype.constructor = ResolvedQueueError; ResolvedQueueError.prototype.constructor = ResolvedQueueError;
var Queue = function() { var Queue = function(thenable) {
var queue = this, var queue = this,
promise_list = [], promise_list = [],
promise, promise,
...@@ -30,6 +30,26 @@ var Queue = function() { ...@@ -30,6 +30,26 @@ var Queue = function() {
} }
} }
function checkPromise(next_promise) {
promise_list.push(next_promise);
// Handle pop
promise_list.push(next_promise.then(function (fulfillmentValue) {
promise_list.splice(0, 2);
if (promise_list.length === 0) {
fulfill(fulfillmentValue);
} else {
return fulfillmentValue;
}
}, function (rejectedReason) {
promise_list.splice(0, 2);
if (promise_list.length === 0) {
reject(rejectedReason);
} else {
throw rejectedReason;
}
}));
}
promise = new Promise(function(done, fail) { promise = new Promise(function(done, fail) {
fulfill = function (fulfillmentValue) { fulfill = function (fulfillmentValue) {
if (resolved) {return;} if (resolved) {return;}
...@@ -47,13 +67,7 @@ var Queue = function() { ...@@ -47,13 +67,7 @@ var Queue = function() {
}; };
}, canceller); }, canceller);
promise_list.push(resolve()); checkPromise(resolve(thenable));
promise_list.push(promise_list[0].then(function () {
promise_list.splice(0, 2);
if (promise_list.length === 0) {
fulfill();
}
}));
queue.cancel = function () { queue.cancel = function () {
if (resolved) {return;} if (resolved) {return;}
...@@ -76,25 +90,9 @@ var Queue = function() { ...@@ -76,25 +90,9 @@ var Queue = function() {
throw new ResolvedQueueError(); throw new ResolvedQueueError();
} }
next_promise = last_promise.then(done, fail);
promise_list.push(next_promise);
// Handle pop // Handle pop
promise_list.push(next_promise.then(function (fulfillmentValue) { checkPromise(last_promise.then(done, fail));
promise_list.splice(0, 2);
if (promise_list.length === 0) {
fulfill(fulfillmentValue);
} else {
return fulfillmentValue;
}
}, function (rejectedReason) {
promise_list.splice(0, 2);
if (promise_list.length === 0) {
reject(rejectedReason);
} else {
throw rejectedReason;
}
}));
return this; return this;
}; };
......
...@@ -2147,9 +2147,9 @@ describe("`RSVP.Queue`", function () { ...@@ -2147,9 +2147,9 @@ describe("`RSVP.Queue`", function () {
}); });
describe("`Queue` constructor", function () { describe("`Queue` constructor", function () {
it('should exist and have length 0', function () { it('should exist and have length 1', function () {
assert(RSVP.Queue); assert(RSVP.Queue);
assert.equal(RSVP.Queue.length, 0); assert.equal(RSVP.Queue.length, 1);
}); });
it('should be a constructor', function () { it('should be a constructor', function () {
...@@ -2240,6 +2240,37 @@ describe("`RSVP.Queue`", function () { ...@@ -2240,6 +2240,37 @@ describe("`RSVP.Queue`", function () {
setTimeout(function() { setTimeout(function() {
assert.equal(queue.isFulfilled, true); assert.equal(queue.isFulfilled, true);
assert.equal(queue.fulfillmentValue, undefined);
done();
}, 20);
});
it('should be fulfilled with the static argument', function (done) {
var queue = new RSVP.Queue('foo');
setTimeout(function() {
assert.equal(queue.isFulfilled, true);
assert.equal(queue.fulfillmentValue, 'foo');
done();
}, 20);
});
it('should be fulfilled with the thenable argument', function (done) {
var queue = new RSVP.Queue(RSVP.resolve('bar'));
setTimeout(function() {
assert.equal(queue.isFulfilled, true);
assert.equal(queue.fulfillmentValue, 'bar');
done();
}, 20);
});
it('should be rejected with the rejected thenable argument', function (done) {
var queue = new RSVP.Queue(RSVP.reject('ko'));
setTimeout(function() {
assert.equal(queue.isRejected, true);
assert.equal(queue.rejectedReason, 'ko');
done(); done();
}, 20); }, 20);
}); });
...@@ -2272,6 +2303,22 @@ describe("`RSVP.Queue`", function () { ...@@ -2272,6 +2303,22 @@ describe("`RSVP.Queue`", function () {
}, 20); }, 20);
}); });
it('`thenable` value is propagated to the next entry', function (done) {
var queue = new RSVP.Queue(RSVP.resolve('foo')),
pushed_result;
queue.push(function (value) {
pushed_result = value;
return "bar";
});
setTimeout(function() {
assert.equal(pushed_result, "foo");
assert.equal(queue.isFulfilled, true);
assert.equal(queue.fulfillmentValue, "bar");
done();
}, 20);
});
it('resolve value is propagated to the next entry', function (done) { it('resolve value is propagated to the next entry', function (done) {
var queue = new RSVP.Queue(), var queue = new RSVP.Queue(),
pushed_result; pushed_result;
...@@ -2319,7 +2366,23 @@ describe("`RSVP.Queue`", function () { ...@@ -2319,7 +2366,23 @@ describe("`RSVP.Queue`", function () {
}, 20); }, 20);
}); });
it('reject cancels the remaining promise', function (done) { it('`thenable` rejection is propagated to the next entry', function (done) {
var queue = new RSVP.Queue(RSVP.timeout(1)),
pushed_result;
queue.push(undefined, function (value) {
pushed_result = value;
throw 'bar';
});
setTimeout(function() {
assert.equal(pushed_result, "Timed out after 1 ms");
assert.equal(queue.isRejected, true);
assert.equal(queue.rejectedReason, "bar");
done();
}, 20);
});
it('rejection is propagated to the next entry', function (done) {
var queue = new RSVP.Queue(), var queue = new RSVP.Queue(),
pushed_result; pushed_result;
queue.push(function () { queue.push(function () {
...@@ -2327,13 +2390,13 @@ describe("`RSVP.Queue`", function () { ...@@ -2327,13 +2390,13 @@ describe("`RSVP.Queue`", function () {
}); });
queue.push(undefined, function (value) { queue.push(undefined, function (value) {
pushed_result = value; pushed_result = value;
throw value; throw 'bar';
}); });
setTimeout(function() { setTimeout(function() {
assert.equal(pushed_result, "Timed out after 1 ms"); assert.equal(pushed_result, "Timed out after 1 ms");
assert.equal(queue.isRejected, true); assert.equal(queue.isRejected, true);
assert.equal(queue.rejectedReason, "Timed out after 1 ms"); assert.equal(queue.rejectedReason, "bar");
done(); done();
}, 20); }, 20);
}); });
...@@ -2413,6 +2476,52 @@ describe("`RSVP.Queue`", function () { ...@@ -2413,6 +2476,52 @@ describe("`RSVP.Queue`", function () {
}, 20); }, 20);
}); });
it('should `cancel` default `thenable`', function (done) {
var thenable_cancel_called = false,
thenable_ongoing = false,
later_success_thenable_called = false,
later_error_thenable_called = false,
queue = new RSVP.Queue(new RSVP.Promise(
function () {
thenable_ongoing = true;
},
function () {
thenable_cancel_called = true;
})
)
.push(
// Should be skipped
function () {later_success_thenable_called = true;},
function () {later_error_thenable_called = true;}
),
result = 'MARKER1',
error = 'MARKER2';
queue.then(function(e) {
result = e;
});
queue.fail(function(e) {
error = e;
});
setTimeout(function() {
assert.equal(queue.isRejected, undefined);
assert.equal(queue.isFulfilled, undefined);
assert.equal(thenable_ongoing, true);
queue.cancel();
assert.equal(thenable_cancel_called, true);
setTimeout(function() {
assert.equal(queue.isRejected, true);
assert.equal(queue.isFulfilled, undefined);
assert(queue.rejectedReason instanceof RSVP.CancellationError);
assert.equal(result, 'MARKER1');
assert(error instanceof RSVP.CancellationError);
assert.equal(later_success_thenable_called, false);
assert.equal(later_error_thenable_called, false);
done();
}, 20);
}, 20);
});
it('should `cancel` pending success `thenable`', function (done) { it('should `cancel` pending success `thenable`', function (done) {
var thenable_cancel_called = false, var thenable_cancel_called = false,
thenable_ongoing = false, thenable_ongoing = false,
......
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