Your logic currently does a lot more work that it needs to do.
First, you are iterating every element in DOM and then iterating on every child element of those (which is actually duplicate work, since all nested tags would already be present in elements
). This is especially problematic in that you are really only interested in text nodes. So, your first order of business, is to get only those nodes you care about.
Perhaps check out this Stack Overflow postthis Stack Overflow post on this topic. I personally like the TreeWalker approach in the accepted answer.
Now that you have a good flattened representation of these text nodes, you can just iterate through and directly modify them.
// build word map
var wordMap = {
'match value': 'replace value',
// etc.
}
// build single regex
var regex = new RegExp(Object.keys(wordMap).join("|"),"gi");
// get text nodes
var textNodes = ...; // derive similar to linked SO question above.
// iterate text nodes and modify in place
for (var i = 0, len = textNodes.length; i < len; i++) {
textNodes[i].nodeValue = textNodes[i].nodeValue.replace(regex, function(match) {
return wordMap[match];
});
}
This example above would have you modifying the nodes in place rather than having to do any DOM replacements.
You could also potentially have some savings by dumping the regex approach to string search altogether in favor of simply iterating through the string a single character at a time comparing against key/property values in your word map, to see if any replacement strings are potentially starting or continuing. You would like need to build a trie structure to give efficient lookup against your dictionary. This is certainly more complex from an implementation standpoint, but could be an optimization you need to make if you find the regex approach is just not operating fast enough for you.
You might find this interesting reading on tries in javascript - http://ejohn.org/blog/javascript-trie-performance-analysis/