Make Polymer.dom.flush reentrant-safe. Fixes #3115.

This commit is contained in:
Kevin Schaaf 2015-11-30 15:01:15 -08:00
parent 203e862976
commit 644105a469
2 changed files with 39 additions and 11 deletions

View File

@ -9,16 +9,16 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
-->
<script>
/**
* `Polymer.dom.flush()` causes any asynchronously queued actions to be
/**
* `Polymer.dom.flush()` causes any asynchronously queued actions to be
* flushed synchronously. It should be used sparingly as calling it frequently
* can negatively impact performance since work is often deferred for
* efficiency. Calling `Polymer.dom.flush()` is useful, for example, when
* an element has to measure itself and is unsure about the state of its
* can negatively impact performance since work is often deferred for
* efficiency. Calling `Polymer.dom.flush()` is useful, for example, when
* an element has to measure itself and is unsure about the state of its
* internal or compoased DOM.
*/
Polymer.Base.extend(Polymer.dom, {
_flushGuard: 0,
_FLUSH_MAX: 100,
_needsTakeRecords: !Polymer.Settings.useNativeCustomElements,
@ -31,8 +31,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
this._flushGuard = 0;
this._prepareFlush();
while (this._debouncers.length && this._flushGuard < this._FLUSH_MAX) {
for (var i=0; i < this._debouncers.length; i++) {
this._debouncers[i].complete();
while (this._debouncers.length) {
this._debouncers.shift().complete();
}
// clear the list of debouncers
if (this._finishDebouncer) {
@ -47,9 +47,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
},
_prepareFlush: function() {
// TODO(sorvell): There is currently not a good way
// TODO(sorvell): There is currently not a good way
// to process all custom elements mutations under SD polyfill because
// these mutations may be inside shadowRoots.
// these mutations may be inside shadowRoots.
// again make any pending CE mutations that might trigger debouncer
// additions go...
if (this._needsTakeRecords) {
@ -76,7 +76,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
addDebouncer: function(debouncer) {
this._debouncers.push(debouncer);
// ensure the list of active debouncers is cleared when done.
this._finishDebouncer = Polymer.Debounce(this._finishDebouncer,
this._finishDebouncer = Polymer.Debounce(this._finishDebouncer,
this._finishFlush);
},

View File

@ -635,6 +635,34 @@ suite('Polymer.dom', function() {
});
test('Polymer.dom.flush reentrancy', function() {
// Setup callbacks
var order = [];
var cb1 = sinon.spy(function() { order.push(cb1); });
var cb2 = sinon.spy(function() { order.push(cb2); });
var cb3 = sinon.spy(function() { order.push(cb3); });
var cb4 = sinon.spy(function() { order.push(cb4); });
var cbReentrant = sinon.spy(function() {
order.push(cbReentrant);
Polymer.dom.addDebouncer(Polymer.Debounce(null, cb3));
Polymer.dom.flush();
Polymer.dom.addDebouncer(Polymer.Debounce(null, cb4));
});
// Enqueue debouncers
Polymer.dom.addDebouncer(Polymer.Debounce(null, cb1));
Polymer.dom.addDebouncer(Polymer.Debounce(null, cbReentrant));
Polymer.dom.addDebouncer(Polymer.Debounce(null, cb2));
// Flush
Polymer.dom.flush();
// Check callbacks called and in correct order
assert.isTrue(cb1.calledOnce);
assert.isTrue(cb2.calledOnce);
assert.isTrue(cb3.calledOnce);
assert.isTrue(cb4.calledOnce);
assert.isTrue(cbReentrant.calledOnce);
assert.sameMembers(order, [cb1, cbReentrant, cb2, cb3, cb4]);
});
});
suite('Polymer.dom accessors', function() {