Plugin for replacing text with HTML I've written a jQuery Plugin which searches text and replaces it with other text or HTML.

Now everything works quite well, but recently I came across this SO question where the OP could have use of my plugin. That's why I linked to the GitHub repo and asked him for critiques and/or contribution.

Soon after, he said that my plugin would have slow down his page by the factor 17 (I don't think this number is coming from the dev console though). Anyway, that comment made me think about how to make my plugin faster.

(function ($) {
    "use strict";
    $.fn.replaceMe = function (options) {
        var settings = $.extend({
            textToReplace: 'any_text',
            replaceWithText: '&lt;span&gt;othertext&lt;/span&gt;',
            globally: true,
            excludedTags: [
                'img',
                'span'
            ]
        }, options);
        $(this).contents().each(function (index, node) {
            var text,
                excludedTags;
            if(node.innerHTML !== undefined) {
                text = node.innerHTML;
            } else {
                text = node.nodeValue;
            }
            excludedTags = (node.localName === null || node.localName === undefined) ? '' : node.localName;
            if (text.match(new RegExp(settings.textToReplace, 'g')) &amp;&amp; node.nodeType === 3 &amp;&amp; !excludedTags.match(new RegExp(settings.excludedTags.join('|')))) {
                if(settings.globally) {
                    $(node).replaceWith(text.replace(new RegExp(settings.textToReplace, 'g'), settings.replaceWithText));
                } else {
                    $(node).replaceWith(text.replace(new RegExp(settings.textToReplace), settings.replaceWithText));
                }
            }
        });
    }
}(jQuery));


On the testing environment, the text to parse counts 169,310 chars or 27,391 words.

The Chrome console says that the script needs 42 ms to perform. Now I'm not sure if the script needs any improvement and if yes what could be done to make it faster.
I would think that a major time complexity comes from the usage of Regex which involves 'steps' in the processing of the expression, meaning the complex the statement, the more steps it can take.

Instead of using a Regex for when settings.globally is false, a normal String.replace can be done.

And instead of using a Regex for the global checks, I would suggest using a String.prototype.replaceAll polyfill like the following:

String.prototype.replaceAll = function(search, replace){
    var string = this;
    var index = 0;
    while ((index = string.indexOf(search)) !== -1) {
        string = string.replace(search, replace);
    }
    return string;
}


Which would change the settings.globally block into:

if(settings.globally) {
    $(node).replaceWith(text.replaceAll(settings.textToReplace, settings.replaceWithText));
} else {
    $(node).replaceWith(text.replace(settings.textToReplace, settings.replaceWithText));
}


I would also suggest removing jQuery from the solution as well. extend, $ (the element fetching), match and each can be polyfilled in, or simply converted to vanilla JavaScript.

function $(selector, el) {
    if (!el) { el = document; }
    return Array.prototype.slice.call(el.querySelectorAll(selector));
}
var extend = function(out) {
  out = out || {};
  for (var i = 1; i &lt; arguments.length; i++) {
    if (!arguments[i])
      continue;
    for (var key in arguments[i]) {
      if (arguments[i].hasOwnProperty(key))
        out[key] = arguments[i][key];
    }
  }
  return out;
};
if (!String.prototype.includes) {
  String.prototype.includes = function() {'use strict';
    return String.prototype.indexOf.apply(this, arguments) !== -1;
  };
}


and for each: you can use Array.prototype.forEach (The polyfill is quite large, so I didn't include it) or a simple for loop.