Skip to content

Commit

Permalink
Use set and clear debouncer upon completion. Fixes #5250
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinpschaaf committed Feb 27, 2019
1 parent e7be356 commit e8d2314
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 28 deletions.
32 changes: 32 additions & 0 deletions lib/utils/debounce.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
this._timer = this._asyncModule.run(() => {
this._timer = null;
this._callback();
debouncerQueue.delete(this);
});
}
/**
Expand Down Expand Up @@ -115,5 +116,36 @@

/** @const */
Polymer.Debouncer = Debouncer;

let debouncerQueue = new Set();

/**
* Adds a `Debouncer` to a list of globally flushable tasks.
*
* @param {!Debouncer} debouncer Debouncer to enqueue
* @return {void}
*/
Polymer.enqueueDebouncer = function(debouncer) {
if (debouncerQueue.has(debouncer)) {
debouncerQueue.delete(debouncer);
}
debouncerQueue.add(debouncer);
};

Polymer.flushDebouncers = function() {
const didFlush = Boolean(debouncerQueue.size);
debouncerQueue.forEach(debouncer => {
try {
debouncer.flush();
} catch(e) {
setTimeout(() => {
throw e;
});
}
});
debouncerQueue = new Set();
return didFlush;
};

})();
</script>
30 changes: 2 additions & 28 deletions lib/utils/flush.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,37 +8,11 @@
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<link rel="import" href="boot.html">
<link rel="import" href="debounce.html">
<script>
(function() {
'use strict';

let debouncerQueue = [];

/**
* Adds a `Polymer.Debouncer` to a list of globally flushable tasks.
*
* @memberof Polymer
* @param {!Polymer.Debouncer} debouncer Debouncer to enqueue
* @return {void}
*/
Polymer.enqueueDebouncer = function(debouncer) {
debouncerQueue.push(debouncer);
};

function flushDebouncers() {
const didFlush = Boolean(debouncerQueue.length);
while (debouncerQueue.length) {
try {
debouncerQueue.shift().flush();
} catch(e) {
setTimeout(() => {
throw e;
});
}
}
return didFlush;
}

/**
* Forces several classes of asynchronously queued tasks to flush:
* - Debouncers added via `enqueueDebouncer`
Expand All @@ -54,7 +28,7 @@
if (window.ShadyCSS && window.ShadyCSS.ScopingShim) {
window.ShadyCSS.ScopingShim.flush();
}
debouncers = flushDebouncers();
debouncers = Polymer.flushDebouncers();
} while (shadyDOM || debouncers);
};

Expand Down
47 changes: 47 additions & 0 deletions test/unit/debounce.html
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,53 @@

});
});

suite('enqueueDebouncer & flush', function() {
function testEnqueue(shouldFlush, done) {
// Longer-running debouncer
const timeoutCallback = sinon.spy(() => actualCallbacks.push(timeoutCallback));
Polymer.enqueueDebouncer(Polymer.Debouncer.debounce(null, Polymer.Async.timeOut, timeoutCallback));
// Set of short-running debouncers enqueued in the middle of first set
const nestedCallbacks = new Array(150).fill().map((_, i) => sinon.spy(() =>
actualCallbacks.push(nestedCallbacks[i])));
// First set of short-running debouncers
const microtaskCallbacks = new Array(150).fill().map((_, i) => sinon.spy(() => {
actualCallbacks.push(microtaskCallbacks[i]);
if (i === 125) {
nestedCallbacks.forEach(cb =>
Polymer.enqueueDebouncer(Polymer.Debouncer.debounce(null, Polymer.Async.microTask, cb)));
}
}));
microtaskCallbacks.forEach(cb =>
Polymer.enqueueDebouncer(Polymer.Debouncer.debounce(null, Polymer.Async.microTask, cb)));
// Expect short before long
let expectedCallbacks;
const actualCallbacks = [];
const verify = () => {
actualCallbacks.forEach(cb => assert.isTrue(cb.calledOnce));
assert.deepEqual(expectedCallbacks, actualCallbacks);
done();
};
if (shouldFlush) {
expectedCallbacks = [timeoutCallback, ...microtaskCallbacks, ...nestedCallbacks];
Polymer.flush();
// When flushing, order is order of enqueing
verify();
} else {
expectedCallbacks = [...microtaskCallbacks, ...nestedCallbacks, timeoutCallback];
Polymer.Async.timeOut.run(verify);
}
}

test('non-flushed', function(done) {
testEnqueue(false, done);
});

test('flushed', function(done) {
testEnqueue(true, done);
});

});
</script>
</body>
</html>

0 comments on commit e8d2314

Please sign in to comment.