diff --git a/lib/utils/debounce.html b/lib/utils/debounce.html
index 5b9e4d2a82..5290285e3b 100644
--- a/lib/utils/debounce.html
+++ b/lib/utils/debounce.html
@@ -39,8 +39,8 @@
this._callback = callback;
this._timer = this._asyncModule.run(() => {
this._timer = null;
- this._callback();
debouncerQueue.delete(this);
+ this._callback();
});
}
/**
@@ -51,7 +51,6 @@
cancel() {
if (this.isActive()) {
this._cancelAsync();
- this._timer = null;
// Canceling a debouncer removes its spot from the flush queue,
// so if a debouncer is manually canceled and re-debounced, it
// will reset its flush order (this is a very minor difference from 1.x)
@@ -65,7 +64,10 @@
* @return {void}
*/
_cancelAsync() {
- this._asyncModule.cancel(/** @type {number} */(this._timer));
+ if (this.isActive()) {
+ this._asyncModule.cancel(/** @type {number} */(this._timer));
+ this._timer = null;
+ }
}
/**
* Flushes an active debouncer and returns a reference to itself.
@@ -158,7 +160,6 @@
});
}
});
- debouncerQueue = new Set();
return didFlush;
};
diff --git a/test/unit/debounce.html b/test/unit/debounce.html
index b380a62185..c9fb0195ea 100644
--- a/test/unit/debounce.html
+++ b/test/unit/debounce.html
@@ -34,6 +34,86 @@
Polymer({is: 'x-basic'});
});
+ suite('enqueueDebouncer & flush', function() {
+
+ // NOTE: This is a regression test; the bug it fixed only occurred if the
+ // debouncer was flushed before any microtasks run, hence it should be
+ // first in this file
+ test('re-enqueue canceled debouncer', function() {
+ const cb = sinon.spy();
+ let db;
+ db = Polymer.Debouncer.debounce(null, Polymer.Async.microTask, cb);
+ Polymer.enqueueDebouncer(db);
+ db.cancel();
+ assert.equal(db.isActive(), false);
+ assert.equal(cb.callCount, 0);
+ db = Polymer.Debouncer.debounce(db, Polymer.Async.microTask, cb);
+ Polymer.enqueueDebouncer(db);
+ Polymer.flush();
+ assert.isTrue(cb.calledOnce);
+ });
+
+ test('flushDebouncers from enqueued debouncer', function(done) {
+ const cb = sinon.spy(() => Polymer.flush());
+ let db = Polymer.Debouncer.debounce(null, Polymer.Async.microTask, cb);
+ Polymer.enqueueDebouncer(db);
+ setTimeout(() => {
+ assert.isTrue(cb.calledOnce);
+ done();
+ });
+ });
+
+ const testEnqueue = (shouldFlush, done) => {
+ const actualOrder = [];
+ const enqueue = (type, {db, cb} = {}) => {
+ cb = cb || (() => actualOrder.push(cb));
+ db = Polymer.Debouncer.debounce(db, type, cb);
+ Polymer.enqueueDebouncer(db);
+ return {db, cb};
+ };
+ const db1 = enqueue(Polymer.Async.microTask);
+ const db2 = enqueue(Polymer.Async.microTask);
+ const db3 = enqueue(Polymer.Async.timeOut);
+ const db4 = enqueue(Polymer.Async.microTask);
+ enqueue(Polymer.Async.microTask, db2);
+ enqueue(Polymer.Async.microTask, db1);
+ if (shouldFlush) {
+ Polymer.flush();
+ assert.deepEqual(actualOrder, [db1.cb, db2.cb, db3.cb, db4.cb]);
+ done();
+ } else {
+ Polymer.Async.timeOut.run(() => {
+ assert.deepEqual(actualOrder, [db4.cb, db2.cb, db1.cb, db3.cb]);
+ done();
+ });
+ }
+ };
+
+ test('non-flushed', function(done) {
+ testEnqueue(false, done);
+ });
+
+ test('flushed', function(done) {
+ testEnqueue(true, done);
+ });
+
+ test('reentrant flush', function() {
+ const cb2 = sinon.spy();
+ let db2;
+ const cb1 = sinon.spy(() => {
+ Polymer.flush();
+ db2 = Polymer.Debouncer.debounce(null, Polymer.Async.microTask, cb2);
+ Polymer.enqueueDebouncer(db2);
+ });
+ const db1 = Polymer.Debouncer.debounce(null, Polymer.Async.microTask, cb1);
+ Polymer.enqueueDebouncer(db1);
+ Polymer.flush();
+ assert.isTrue(cb1.calledOnce);
+ assert.isTrue(cb2.calledOnce);
+ });
+
+ });
+
suite('debounce', function() {
var element;
@@ -208,43 +288,6 @@
});
});
- });
-
- suite('enqueueDebouncer & flush', function() {
-
- const testEnqueue = (shouldFlush, done) => {
- const actualOrder = [];
- const enqueue = (type, {db, cb} = {}) => {
- cb = cb || (() => actualOrder.push(cb));
- db = Polymer.Debouncer.debounce(db, type, cb);
- Polymer.enqueueDebouncer(db);
- return {db, cb};
- };
- const db1 = enqueue(Polymer.Async.microTask);
- const db2 = enqueue(Polymer.Async.microTask);
- const db3 = enqueue(Polymer.Async.timeOut);
- const db4 = enqueue(Polymer.Async.microTask);
- enqueue(Polymer.Async.microTask, db2);
- enqueue(Polymer.Async.microTask, db1);
- if (shouldFlush) {
- Polymer.flush();
- assert.deepEqual(actualOrder, [db1.cb, db2.cb, db3.cb, db4.cb]);
- done();
- } else {
- Polymer.Async.timeOut.run(() => {
- assert.deepEqual(actualOrder, [db4.cb, db2.cb, db1.cb, db3.cb]);
- done();
- });
- }
- };
-
- test('non-flushed', function(done) {
- testEnqueue(false, done);
- });
-
- test('flushed', function(done) {
- testEnqueue(true, done);
- });
});