Javascript code too slow in Firefox extension using Storage service
I'm running the following javascript code in firefox extension
highlightLinks: function(e) {
var anchors = e.target.getElementsByTagName("a");
let file = Components.classes["@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties)
.get("ProfD", Components.interfaces.nsIFile);
file.append("test.sqlite");
var storageService = Components.classes["@mozilla.org/storage/service;1"]
.getService(Components.interfaces.mozIStorageService);
var conn = storageService.openDatabase(file);
for (var i = 0; i < anchors.length; i++) {
var statement = conn.createStatement("select * from links where url=?1");
statement.bindStringParameter(0, anchors[i].href);
var visited = false;
try {
while (statement.executeStep()) {
visited = true;
break;
}
} catch (e) {
} finally {
statement.reset();
}
statement.finalize();
if (visited) {
anchors[i].innerHTML += "+";
}
}
conn.close();
},
This function runs on DOMContentLoaded event. It checks for every link on the page if it's present in the test.sqlite
database and markes the links that are present.
The problem is that the loading of pages is much slower now (especially when I lower CPU frequency). Could you help me make this code more efficient and resour开发者_Go百科ce saving?
Edit : Significant speedup was achieved by removing event listener at the and of the function.
thank you
It'll be faster if you pull the createStatement
out of the loop, and reuse it, rebinding the parameters each time. The docs for storage say: "Note: If you need to execute a statement multiple times, caching the result of createStatement will give you a noticeable performance improvement because the SQL query does not need to be parsed each time."
So instead of:
for (var i = 0; i < anchors.length; i++) {
var statement = conn.createStatement("select * from links where url=?1");
statement.bindStringParameter(0, anchors[i].href);
// ... do stuff with results
write:
var statement = conn.createStatement("select * from links where url=?1");
for (var i = 0; i < anchors.length; i++) {
statement.bindStringParameter(0, anchors[i].href);
// ... do stuff with results
Edit: Also, if you're using a recent Firefox, you can use their asynchronous API to avoid delaying the UI. Instead of calling executeStep
, use executeAsync instead.
statement.executeAsync({
handleResult: function(aResultSet) {
// ... do stuff with results
},
handleError: function(aError) {
print("Error: " + aError.message);
},
handleCompletion: function(aReason) {
if (aReason != Components.interfaces.mozIStorageStatementCallback.REASON_FINISHED)
print("Query canceled or aborted!");
}
});
In general when you call a database(not the browser ones) it is better to make one call, fetch all the data you will need into an array or an hash, and then work with them internally.
EDIT:
I would do that: load from the storage all the links and build a hash like:
linksHash = {
'url-1':true,
...,
'url-n':true
}
Then loop on anchors
and make a check with something like:
if(linksHash[anchors[i].href]){
//the link href is in the hash
}
Then if you note the RAM becomes an issue cut the load of the table in 2 or more pieces.
first tip, altough it won't save too much time, is not using anchors.length in the condition of the for-loop. better use:
for(var i = 0, num = anchors.length; i < num, i++) {...}
精彩评论