I have been trying different methods of doing this, however they are all quite slow.
noGlobalTags is an array containing three tags.
Method 1:
var textNodeWalker = document.createTreeWalker(node, NodeFilter.SHOW_TEXT, function(node){return (noGlobalTags.indexOf(node.tagName)==-1)? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;}, false);
var cn;
while(cn = textNodeWalker.nextNode()){
textNodeEmoteParser(cn);
}
return;
Method 2:
function getTextNodes(node) {
if(node.nodeType == 3) {
textNodeEmoteParser(node);
} else {
for(var i = 0, len = node.childNodes.length; i < len; ++i) {
if(noGlobalTags.indexOf(node.childNodes[i].tagName)!=-1) {
continue;
}
getTextNodes(node.childNodes[i]);
}
}
}
getTextNodes(node);
I had expected method 1 to be the quickest, however it took double as long as the second method. Am I doing something stupid here? If not, can I make it faster than the second method?
In javascript, inline code (as in the 2nd example), is nearly always faster than using callbacks (as in the 1st example). Javascript has a meaningful amount of overhead for a function call.
So, the generic treeWalker method with callbacks isn’t as likely to every be as fast as a direct coded method in your 2nd example.
One finds the same thing is true when comparing a
forloop direct iteration of an array to a.forEach()iteration of the same array for the same reaons. Callback functions are slow.The code with callback functions can often be more generically useful and sometimes much shorter, but not necessarily faster to execute.
This shouldn’t be surprising if you think about what’s happening in javascript. To call a function, it has to do a lookup of the name, then it has to create a new function context, pass the parameters to the function, create any local variables in that function, execute the code in that function, clean up all of the above when done, return from that function and continuing execution after the function call. The inline code version skips a lot of these steps.
FYI, you can speed both of them up if you put the tags in an object instead of an array:
Then, you can check if a given tag is in that list with this type of code:
or
which should be significantly faster than the array search you are currently using.
Here’s a non-recursive version that also uses the faster noGlobalTags lookup:
EDIT: nearly 100x faster. I found a different method that actually just walks the tree directly that is a lot faster:
JSPerf here: http://jsperf.com/get-text-nodes-non-recursive/3