Client sync queue: better logic around setTimeout

In the old code, if you queued a task, did something which flushes the
queue (runTask, flush, or drain), and then queued another task, you'd
end up with two pending timeouts, rather than zero. With this change,
we're careful to never have two pending timeouts, and also to clear the
timeout if we're about to run all current tasks.
This commit is contained in:
David Glasser
2014-08-05 14:50:21 -07:00
parent 835eb66377
commit 3d75f53149

View File

@@ -14,6 +14,7 @@ Meteor._SynchronousQueue = function () {
var self = this;
self._tasks = [];
self._running = false;
self._runTimeout = null;
};
_.extend(Meteor._SynchronousQueue.prototype, {
@@ -25,6 +26,15 @@ _.extend(Meteor._SynchronousQueue.prototype, {
var tasks = self._tasks;
self._tasks = [];
self._running = true;
if (self._runTimeout) {
// Since we're going to drain the queue, we can forget about the timeout
// which tries to run it. (But if one of our tasks queues something else,
// the timeout will be correctly re-created.)
clearTimeout(self._runTimeout);
self._runTimeout = null;
}
try {
while (!_.isEmpty(tasks)) {
var t = tasks.shift();
@@ -47,12 +57,12 @@ _.extend(Meteor._SynchronousQueue.prototype, {
queueTask: function (task) {
var self = this;
var wasEmpty = _.isEmpty(self._tasks);
self._tasks.push(task);
// Intentionally not using Meteor.setTimeout, because it doesn't like runing
// in stubs for now.
if (wasEmpty)
setTimeout(_.bind(self.flush, self), 0);
if (!self._runTimeout) {
self._runTimeout = setTimeout(_.bind(self.flush, self), 0);
}
},
flush: function () {