Skip to content

Commit 1137a0a

Browse files
committed
Use set and clear debouncer upon completion. Fixes #5250
1 parent 5788df2 commit 1137a0a

File tree

3 files changed

+81
-28
lines changed

3 files changed

+81
-28
lines changed

lib/utils/debounce.html

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
this._timer = this._asyncModule.run(() => {
4141
this._timer = null;
4242
this._callback();
43+
debouncerQueue.delete(this);
4344
});
4445
}
4546
/**
@@ -115,5 +116,36 @@
115116

116117
/** @const */
117118
Polymer.Debouncer = Debouncer;
119+
120+
let debouncerQueue = new Set();
121+
122+
/**
123+
* Adds a `Debouncer` to a list of globally flushable tasks.
124+
*
125+
* @param {!Debouncer} debouncer Debouncer to enqueue
126+
* @return {void}
127+
*/
128+
Polymer.enqueueDebouncer = function(debouncer) {
129+
if (debouncerQueue.has(debouncer)) {
130+
debouncerQueue.delete(debouncer);
131+
}
132+
debouncerQueue.add(debouncer);
133+
};
134+
135+
Polymer.flushDebouncers = function() {
136+
const didFlush = Boolean(debouncerQueue.size);
137+
debouncerQueue.forEach(debouncer => {
138+
try {
139+
debouncer.flush();
140+
} catch(e) {
141+
setTimeout(() => {
142+
throw e;
143+
});
144+
}
145+
});
146+
debouncerQueue = new Set();
147+
return didFlush;
148+
};
149+
118150
})();
119151
</script>

lib/utils/flush.html

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,37 +8,11 @@
88
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
99
-->
1010
<link rel="import" href="boot.html">
11+
<link rel="import" href="debounce.html">
1112
<script>
1213
(function() {
1314
'use strict';
1415

15-
let debouncerQueue = [];
16-
17-
/**
18-
* Adds a `Polymer.Debouncer` to a list of globally flushable tasks.
19-
*
20-
* @memberof Polymer
21-
* @param {!Polymer.Debouncer} debouncer Debouncer to enqueue
22-
* @return {void}
23-
*/
24-
Polymer.enqueueDebouncer = function(debouncer) {
25-
debouncerQueue.push(debouncer);
26-
};
27-
28-
function flushDebouncers() {
29-
const didFlush = Boolean(debouncerQueue.length);
30-
while (debouncerQueue.length) {
31-
try {
32-
debouncerQueue.shift().flush();
33-
} catch(e) {
34-
setTimeout(() => {
35-
throw e;
36-
});
37-
}
38-
}
39-
return didFlush;
40-
}
41-
4216
/**
4317
* Forces several classes of asynchronously queued tasks to flush:
4418
* - Debouncers added via `enqueueDebouncer`
@@ -54,7 +28,7 @@
5428
if (window.ShadyCSS && window.ShadyCSS.ScopingShim) {
5529
window.ShadyCSS.ScopingShim.flush();
5630
}
57-
debouncers = flushDebouncers();
31+
debouncers = Polymer.flushDebouncers();
5832
} while (shadyDOM || debouncers);
5933
};
6034

test/unit/debounce.html

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,53 @@
209209

210210
});
211211
});
212+
213+
suite('enqueueDebouncer & flush', function() {
214+
function testEnqueue(shouldFlush, done) {
215+
// Longer-running debouncer
216+
const timeoutCallback = sinon.spy(() => actualCallbacks.push(timeoutCallback));
217+
Polymer.enqueueDebouncer(Polymer.Debouncer.debounce(null, Polymer.Async.timeOut, timeoutCallback));
218+
// Set of short-running debouncers enqueued in the middle of first set
219+
const nestedCallbacks = new Array(150).fill().map((_, i) => sinon.spy(() =>
220+
actualCallbacks.push(nestedCallbacks[i])));
221+
// First set of short-running debouncers
222+
const microtaskCallbacks = new Array(150).fill().map((_, i) => sinon.spy(() => {
223+
actualCallbacks.push(microtaskCallbacks[i]);
224+
if (i === 125) {
225+
nestedCallbacks.forEach(cb =>
226+
Polymer.enqueueDebouncer(Polymer.Debouncer.debounce(null, Polymer.Async.microTask, cb)));
227+
}
228+
}));
229+
microtaskCallbacks.forEach(cb =>
230+
Polymer.enqueueDebouncer(Polymer.Debouncer.debounce(null, Polymer.Async.microTask, cb)));
231+
// Expect short before long
232+
let expectedCallbacks;
233+
const actualCallbacks = [];
234+
const verify = () => {
235+
actualCallbacks.forEach(cb => assert.isTrue(cb.calledOnce));
236+
assert.deepEqual(expectedCallbacks, actualCallbacks);
237+
done();
238+
};
239+
if (shouldFlush) {
240+
expectedCallbacks = [timeoutCallback, ...microtaskCallbacks, ...nestedCallbacks];
241+
Polymer.flush();
242+
// When flushing, order is order of enqueing
243+
verify();
244+
} else {
245+
expectedCallbacks = [...microtaskCallbacks, ...nestedCallbacks, timeoutCallback];
246+
Polymer.Async.timeOut.run(verify);
247+
}
248+
}
249+
250+
test('non-flushed', function(done) {
251+
testEnqueue(false, done);
252+
});
253+
254+
test('flushed', function(done) {
255+
testEnqueue(true, done);
256+
});
257+
258+
});
212259
</script>
213260
</body>
214261
</html>

0 commit comments

Comments
 (0)