From 3d75f53149183d0ec60ccdf33faf75fcb8d6729c Mon Sep 17 00:00:00 2001 From: David Glasser Date: Tue, 5 Aug 2014 14:50:21 -0700 Subject: [PATCH] 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. --- packages/meteor/fiber_stubs_client.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/meteor/fiber_stubs_client.js b/packages/meteor/fiber_stubs_client.js index 3babd0e08f..c11118d0a6 100644 --- a/packages/meteor/fiber_stubs_client.js +++ b/packages/meteor/fiber_stubs_client.js @@ -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 () {