Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Unified Diff: lib/elemHide.js

Issue 29342830: Issue 4057 - Further speedup ElemHide.getSelectorsforDomain (Closed)
Patch Set: Rebased, unconditionalSelectors Created May 24, 2016, 2:39 p.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | test/elemHide.js » ('j') | test/elemHide.js » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/elemHide.js
diff --git a/lib/elemHide.js b/lib/elemHide.js
index 574ef91dff6340a1e9408571fef1b31726cec78c..e0d2c5e10b89334988094b84d7c06ea552b652dd 100644
--- a/lib/elemHide.js
+++ b/lib/elemHide.js
@@ -40,17 +40,30 @@ var filterByKey = [];
var keyByFilter = Object.create(null);
/**
- * Nested lookup table, filter (or false if inactive) by filter text by domain
+ * Indicates whether we are using the getSelectorsForDomain function and
+ * therefore mainting the required filtersByDomain, filtersBySelector and
+ * unconditionalSelectors lookups. (Will be false for Firefox)
+ * @type Boolean
+ */
+var usingGetSelectorsForDomain = !("nsIStyleSheetService" in Ci);
+
+/**
+ * Nested lookup table, filter (or false if inactive) by filter key by domain.
+ * (Only contains filters that aren't unconditionally matched for all domains.)
* @type Object
*/
var filtersByDomain = Object.create(null);
/**
- * Indicates whether we are using (and maintaining) the filtersByDomain lookup.
- * (Will be false for Firefox)
- * @type Boolean
+ * Lookup table, filters by selector. (Only contains filters that have a
+ * selector that is unconditionally matched for all domains.)
*/
-var usingFiltersByDomain = !("nsIStyleSheetService" in Ci);
+var filtersBySelector = Object.create(null);
+
+/**
+ * Array of selectors which unconditionally apply to all domains.
+ */
+var unconditionalSelectors = [];
/**
* Object to be used instead when a filter has a blank domains property.
@@ -119,12 +132,31 @@ var ElemHide = exports.ElemHide =
filterByKey = [];
keyByFilter = Object.create(null);
filtersByDomain = Object.create(null);
+ filtersBySelector = Object.create(null);
+ unconditionalSelectors = [];
knownExceptions = Object.create(null);
exceptions = Object.create(null);
ElemHide.isDirty = false;
ElemHide.unapply();
},
+ _addToFiltersByDomain: function(filter)
+ {
+ let key = keyByFilter[filter.text];
+ let domains = filter.domains || defaultDomains;
+ for (let domain in domains)
+ {
+ let filters = filtersByDomain[domain];
+ if (!filters)
+ filters = filtersByDomain[domain] = Object.create(null);
+
+ if (domains[domain])
+ filters[key] = filter;
+ else
+ filters[key] = false;
+ }
+ },
+
/**
* Add a new element hiding filter
* @param {ElemHideFilter} filter
@@ -140,6 +172,23 @@ var ElemHide = exports.ElemHide =
if (!(selector in exceptions))
exceptions[selector] = [];
exceptions[selector].push(filter);
+
+ if (usingGetSelectorsForDomain)
+ {
+ // If this is the first exception for a previously unconditionally
+ // applied element hiding selector we need to take care to update the
+ // lookups.
+ let unconditionalFilters = filtersBySelector[selector];
+ if (unconditionalFilters)
+ {
+ for (let f of unconditionalFilters)
+ this._addToFiltersByDomain(f);
+ delete filtersBySelector[selector];
+ let index = unconditionalSelectors.indexOf(selector);
+ unconditionalSelectors.splice(index, 1);
+ }
+ }
+
knownExceptions[filter.text] = true;
}
else
@@ -150,19 +199,26 @@ var ElemHide = exports.ElemHide =
let key = filterByKey.push(filter) - 1;
keyByFilter[filter.text] = key;
- if (usingFiltersByDomain)
+ if (usingGetSelectorsForDomain)
{
- let domains = filter.domains || defaultDomains;
- for (let domain in domains)
+ // The new filter's selector is unconditionally applied to all domains
Wladimir Palant 2016/05/24 15:16:18 This comment belongs inside the if block since it
kzar 2016/05/25 05:12:24 Done.
+ if (!filter.domains && !exceptions[filter.selector])
Wladimir Palant 2016/05/24 15:16:19 We don't really care about the value of exceptions
kzar 2016/05/25 05:12:24 Done.
{
- let filters = filtersByDomain[domain];
- if (!filters)
- filters = filtersByDomain[domain] = Object.create(null);
-
- if (domains[domain])
- filters[filter.text] = filter;
+ let filters = filtersBySelector[filter.selector];
+ if (filters)
+ {
+ filters.push(filter);
+ }
else
- filters[filter.text] = false;
+ {
+ filtersBySelector[filter.selector] = [filter];
+ unconditionalSelectors.push(filter.selector);
+ }
+ }
+ // The new filter's selector only applies to some domains
Wladimir Palant 2016/05/24 15:16:18 Same here, comment inside the block please.
kzar 2016/05/25 05:12:24 Done.
+ else
+ {
+ this._addToFiltersByDomain(filter);
}
}
@@ -197,14 +253,32 @@ var ElemHide = exports.ElemHide =
delete keyByFilter[filter.text];
ElemHide.isDirty = true;
- if (usingFiltersByDomain)
+ if (usingGetSelectorsForDomain)
kzar 2016/05/24 14:45:22 I'm worried about the performance of ElemHide.remo
Wladimir Palant 2016/05/24 15:16:19 A remove isn't a very common operation. Did you me
kzar 2016/05/24 17:47:09 Yea, it's pretty bad - something like 2325ms spent
kzar 2016/05/24 17:52:12 Another idea, maybe crazy... removing is expensive
kzar 2016/05/25 04:57:16 With Patch Set 5 ElemHide.remove is now down to ab
{
- let domains = filter.domains || defaultDomains;
- for (let domain in domains)
+ let filters = filtersBySelector[filter.selector];
+ if (filters)
{
- let filters = filtersByDomain[domain];
- if (filters)
- delete filters[filter.text];
+ if (filters.length > 1)
+ {
+ let index = filters.indexOf(filter);
+ filters.splice(index, 1);
+ }
+ else
+ {
+ delete filtersBySelector[filter.selector];
+ let index = unconditionalSelectors.indexOf(filter.selector);
+ unconditionalSelectors.splice(index, 1);
+ }
+ }
+ else
+ {
+ let domains = filter.domains || defaultDomains;
+ for (let domain in domains)
+ {
+ let filters = filtersByDomain[domain];
+ if (filters)
+ delete filters[key];
+ }
}
}
}
@@ -416,11 +490,11 @@ var ElemHide = exports.ElemHide =
/**
* Returns a list of all selectors active on a particular domain, must not be
- * used in Firefox (when usingFiltersByDomain is false).
+ * used in Firefox (when usingGetSelectorsForDomain is false).
*/
getSelectorsForDomain: function(/**String*/ domain, /**Boolean*/ specificOnly)
{
- if (!usingFiltersByDomain)
+ if (!usingGetSelectorsForDomain)
throw new Error("getSelectorsForDomain can not be used in Firefox!");
let selectors = [];
@@ -435,13 +509,13 @@ var ElemHide = exports.ElemHide =
let filters = filtersByDomain[currentDomain];
if (filters)
{
- for (let filterText in filters)
+ for (let filterKey in filters)
{
- if (filterText in seenFilters)
+ if (filterKey in seenFilters)
continue;
- seenFilters[filterText] = true;
+ seenFilters[filterKey] = true;
- let filter = filters[filterText];
+ let filter = filters[filterKey];
if (filter && !this.getException(filter, domain))
selectors.push(filter.selector);
}
@@ -454,6 +528,9 @@ var ElemHide = exports.ElemHide =
currentDomain = nextDot == -1 ? "" : currentDomain.substr(nextDot + 1);
}
- return selectors;
+ if (specificOnly)
Sebastian Noack 2016/05/24 15:20:07 Why do you still account for specificOnly inside t
Wladimir Palant 2016/05/24 15:26:06 Not all generic filters are in unconditionalSelect
+ return selectors;
+ else
Sebastian Noack 2016/05/24 15:20:07 Nit: extraneous else
kzar 2016/05/25 05:12:24 Done.
+ return unconditionalSelectors.concat(selectors);
Wladimir Palant 2016/05/24 15:16:19 I think we should avoid concatenating two arrays h
kzar 2016/05/25 05:12:24 Done.
}
};
« no previous file with comments | « no previous file | test/elemHide.js » ('j') | test/elemHide.js » ('J')

Powered by Google App Engine
This is Rietveld