Bug 982322 - Part 5: Delay node registrations. r=ochameau

This commit is contained in:
"J. Ryan Stinnett" 2014-03-17 12:06:00 +01:00
Родитель 501fd20bf9
Коммит 293334dacc
1 изменённых файлов: 30 добавлений и 13 удалений

Просмотреть файл

@ -70,6 +70,8 @@ function Template(root, store, l10nResolver) {
this._root = root; this._root = root;
this._doc = this._root.ownerDocument; this._doc = this._root.ownerDocument;
this._queuedNodeRegistrations = [];
this._storeChanged = this._storeChanged.bind(this); this._storeChanged = this._storeChanged.bind(this);
this._store.on("set", this._storeChanged); this._store.on("set", this._storeChanged);
} }
@ -77,6 +79,7 @@ function Template(root, store, l10nResolver) {
Template.prototype = { Template.prototype = {
start: function() { start: function() {
this._processTree(this._root); this._processTree(this._root);
this._registerQueuedNodes();
}, },
destroy: function() { destroy: function() {
@ -99,6 +102,8 @@ Template.prototype = {
this._invalidate(registeredPath); this._invalidate(registeredPath);
} }
} }
this._registerQueuedNodes();
}, },
_invalidate: function(path) { _invalidate: function(path) {
@ -127,24 +132,36 @@ Template.prototype = {
} }
}, },
_registerNode: function(path, element) { // Delay node registration until the last step of starting / updating the UI.
// This allows us to avoid doing double work in _storeChanged where the first
// call to |_invalidate| registers new nodes, which would then be visited a
// second time when it iterates over node listeners.
_queueNodeRegistration: function(path, element) {
this._queuedNodeRegistrations.push([path, element]);
},
// We map a node to a path. _registerQueuedNodes: function() {
// If the value behind this path is updated, for (let [path, element] of this._queuedNodeRegistrations) {
// we get notified from the ObjectEmitter, // We map a node to a path.
// and then we know which objects to update. // If the value behind this path is updated,
// we get notified from the ObjectEmitter,
if (!this._nodeListeners.has(path)) { // and then we know which objects to update.
this._nodeListeners.set(path, new Set()); if (!this._nodeListeners.has(path)) {
this._nodeListeners.set(path, new Set());
}
let set = this._nodeListeners.get(path);
set.add(element);
} }
let set = this._nodeListeners.get(path); this._queuedNodeRegistrations.length = 0;
set.add(element);
}, },
_unregisterNodes: function(nodes) { _unregisterNodes: function(nodes) {
for (let e of nodes) { for (let e of nodes) {
for (let registeredPath of e.registeredPaths) { for (let registeredPath of e.registeredPaths) {
let set = this._nodeListeners.get(registeredPath); let set = this._nodeListeners.get(registeredPath);
if (!set) {
continue;
}
set.delete(e); set.delete(e);
if (set.size === 0) { if (set.size === 0) {
this._nodeListeners.delete(registeredPath); this._nodeListeners.delete(registeredPath);
@ -195,8 +212,8 @@ Template.prototype = {
} }
// paths is an array that will store all the paths we needed // paths is an array that will store all the paths we needed
// to expand the node. We will then, via _registerNode, link // to expand the node. We will then, via
// this element to these paths. // _registerQueuedNodes, link this element to these paths.
let paths = []; let paths = [];
@ -239,7 +256,7 @@ Template.prototype = {
} }
if (paths.length > 0) { if (paths.length > 0) {
for (let path of paths) { for (let path of paths) {
this._registerNode(path, e); this._queueNodeRegistration(path, e);
} }
} }
// Store all the paths on the node, to speed up unregistering later // Store all the paths on the node, to speed up unregistering later