Skip to content

Commit b9d4959

Browse files
committed
Fix order of flushed debouncers to match 1.x
1 parent 567c10b commit b9d4959

File tree

2 files changed

+43
-44
lines changed

2 files changed

+43
-44
lines changed

lib/utils/debounce.js

+14-7
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,19 @@ export class Debouncer {
4545
*/
4646
cancel() {
4747
if (this.isActive()) {
48-
this._asyncModule.cancel(/** @type {number} */(this._timer));
48+
this._cancelAsync();
4949
this._timer = null;
5050
debouncerQueue.delete(this);
5151
}
5252
}
53+
/**
54+
* Cancels a debouncer's async callback.
55+
*
56+
* @return {void}
57+
*/
58+
_cancelAsync() {
59+
this._asyncModule.cancel(/** @type {number} */(this._timer));
60+
}
5361
/**
5462
* Flushes an active debouncer and returns a reference to itself.
5563
*
@@ -105,7 +113,9 @@ export class Debouncer {
105113
*/
106114
static debounce(debouncer, asyncModule, callback) {
107115
if (debouncer instanceof Debouncer) {
108-
debouncer.cancel();
116+
// Cancel the async callback, but leave in debouncerQueue if it was
117+
// enqueued, to maintain 1.x flush order
118+
debouncer._cancelAsync();
109119
} else {
110120
debouncer = new Debouncer();
111121
}
@@ -123,14 +133,11 @@ let debouncerQueue = new Set();
123133
* @return {void}
124134
*/
125135
export const enqueueDebouncer = function(debouncer) {
126-
// Re-enqueued debouncers are put at the end of the queue; for Set, this
127-
// means removing and re-adding, since forEach traverses insertion order
128-
if (debouncerQueue.has(debouncer)) {
129-
debouncerQueue.delete(debouncer);
130-
}
131136
debouncerQueue.add(debouncer);
132137
};
133138

139+
window.debouncerQueue = debouncerQueue;
140+
134141
/**
135142
* Flushes any enqueued debouncers
136143
*

test/unit/debounce.html

+29-37
Original file line numberDiff line numberDiff line change
@@ -212,56 +212,48 @@
212212
});
213213

214214
suite('enqueueDebouncer & flush', function() {
215-
function testEnqueue(shouldFlush, done) {
216-
// Longer-running debouncer
217-
const timeoutCallback = sinon.spy(() => actualCallbacks.push(timeoutCallback));
218-
enqueueDebouncer(Debouncer.debounce(null, timeOut, timeoutCallback));
219-
// Set of short-running debouncers enqueued in the middle of first set
220-
const nestedCallbacks = [];
221-
for (let i=0; i<150; i++) {
222-
nestedCallbacks.push(sinon.spy(() =>
223-
actualCallbacks.push(nestedCallbacks[i])));
224-
}
225-
// First set of short-running debouncers
226-
const microtaskCallbacks = [];
227-
for (let i=0; i<150; i++) {
228-
microtaskCallbacks.push(sinon.spy(() => {
229-
actualCallbacks.push(microtaskCallbacks[i]);
230-
if (i === 125) {
231-
nestedCallbacks.forEach(cb =>
232-
enqueueDebouncer(Debouncer.debounce(null, microTask, cb)));
233-
}
234-
}));
235-
}
236-
microtaskCallbacks.forEach(cb =>
237-
enqueueDebouncer(Debouncer.debounce(null, microTask, cb)));
238-
// Expect short before long
239-
let expectedCallbacks;
240-
const actualCallbacks = [];
241-
const verify = () => {
242-
actualCallbacks.forEach(cb => assert.isTrue(cb.calledOnce));
243-
assert.deepEqual(expectedCallbacks, actualCallbacks);
244-
done();
215+
216+
const testEnqueue = (shouldFlush, done) => {
217+
const actualOrder = [];
218+
let i=1;
219+
const enqueue = (type, {db, cb} = {}) => {
220+
// cb = cb || (() => actualOrder.push(cb));
221+
if (!cb) {
222+
cb = (() => actualOrder.push(cb));
223+
Object.defineProperty(cb, 'name', {value: `db${i}`}); i++;
224+
}
225+
db = Debouncer.debounce(db, type, cb);
226+
enqueueDebouncer(db);
227+
return {db, cb};
245228
};
229+
const db1 = enqueue(microTask);
230+
const db2 = enqueue(microTask);
231+
const db3 = enqueue(timeOut);
232+
const db4 = enqueue(microTask);
233+
enqueue(microTask, db2);
234+
enqueue(microTask, db1);
246235
if (shouldFlush) {
247-
expectedCallbacks = [timeoutCallback, ...microtaskCallbacks, ...nestedCallbacks];
248236
flush();
249-
// When flushing, order is order of enqueing
250-
verify();
237+
assert.deepEqual(actualOrder, [db1.cb, db2.cb, db3.cb, db4.cb]);
238+
done();
251239
} else {
252-
expectedCallbacks = [...microtaskCallbacks, ...nestedCallbacks, timeoutCallback];
253-
timeOut.run(verify);
240+
timeOut.run(() => {
241+
assert.deepEqual(actualOrder, [db4.cb, db2.cb, db1.cb, db3.cb]);
242+
done();
243+
});
254244
}
255-
}
245+
};
256246

257247
test('non-flushed', function(done) {
258248
testEnqueue(false, done);
259249
});
260250

261-
test('flushed', function(done) {
251+
test.only('flushed', function(done) {
262252
testEnqueue(true, done);
263253
});
264254

255+
test('re-enqueued ')
256+
265257
});
266258
});
267259
</script>

0 commit comments

Comments
 (0)