new String replaceAll Javascript not so powerful

There’s a new javascript function in the String prototype, called replaceAll.

We all tried the native replace function, to find that it only replace the first occurrence, and we have to use a regex to really replace all, like this:
“the blue fox”.replace(/blue/g, “red”);

Now, the replaceAll does what we hope, by replacing all “string1” with “string2”, in the whole string instance, returning a copy of it.

But, in the meantime, lots of people tried to create their own replaceAll function, and one of them was to use the split / join trick. We found that it’s also very powerful when we need to manage large strings, or with a large amount of strings to convert.

So, I tried to see if I can replace all my split-join usage, with the new replaceAll.
And, the answer is NO!
Instead, I will make sure I never use the new replaceall, and I’ll keep my old custom function.

The split-join is, depending on the length of the input / find / replaceBy variables, up to 5 times faster in the tests I did.
Sometimes, it’s the same speed, but most of the time, it’s faster. And, in Chrome 85, it’s never slower.

Test code:

    <button onclick="test_replaceAll();">replaceAll</button>
    <button onclick="test_split();">split</button>
    <script>
      console.clear()
      var i = 25;
      var s = "asdf".repeat(i * 100000);
      var sFrom = "sd";
      var sTo = "z".repeat(i);

      function test_replaceAll(){
        var t0 = (new Date()).getTime();
        var t1 = s.replaceAll(sFrom, sTo);
        console.log("t1", t1.length, (new Date()).getTime() - t0);
      }

      function test_split(){
        var t0 = (new Date()).getTime();
        var t2 = s.split(sFrom).join(sTo);
        console.log("t2", t2.length, (new Date()).getTime() - t0);
      }
    </script>

Look at these results: First 5 are “replace”, last 5 are “split/join”

replaceAll: 750ms
split/join: 250ms

There’s no doubt that the split/join method is still the fastest.

But, if you need to use “regex” instead, now the replaceAll is the one to use.

High performance JavaScript htmlEncode

I recently had to encode lot of strings to HTML in client-side javascript.  There’s a lot of find-replace procedures we can find all over the web, but I think that the most reliable way to encode string is to use the browser itself.

One very easy method to encode a string, that we find everywhere, is this one: 

function htmlEncode(_s){
  return $("<span />").text(_s).html()
}

If we use that quick jQuery function, we know that the result is totally safe, by allowing the browser to do the job on our behalf.

But, using the DOM is sometimes the cause of a slow application…
Does this method is reliable if we need to convert thousands of strings?

I did the test, by repeating the conversion 100000 times.

The previous function, creates a new “span” on every call, and modify the innerHTML of it.

Chrome console “performance monitor” shows that there are 3 DOM nodes created on each call. It takes an average of 2200 ms to run the loop, and generates lots of garbage collection to remove these old DOM items.

Take 2

So, let’s try to re-use the previous span instead without re-creating it.

var $span;
function htmlEncode(_s){
   $span = $span || $('<span />');
   return $span.text(_s).html();
}

This time, on each call, 2 DOM nodes instead of 3 are created.
And, the average time goes down to 1600 ms instead of 2200.

Take 3

Then, I tried to see what jQuery does, to see if it’s possible to re-use the inner text objects that are re-created on each call.

Now, try that 100% non-jquery method. (That you can achieve by using jquery and editing the childNodes directlly…)

var spn, txt;
function htmlEncode(_s){
   if (!spn) {
      spn = document.createElement("span");
      txt = document.createTextNode("");
      spn.appendChild(txt);
   }
   txt.data = _s;
   return spn.innerHTML;
}

That final version of our custom htmlEncode function looks very powerful!

Now, 0 nodes are created on each loop (3 on the first call), we always re-use the same 3 nodes.
And, the loop time is now 100 ms, with absolutely no garbage collection!

Summary

Look at these analysis from the Chrome console.

You can try it by yourself on that demo page I used to generate the previous tests.