DEV Community

Cover image for The fantastic speed of template literals...
Eckehard
Eckehard

Posted on

The fantastic speed of template literals...

Template literals (sometimes called template strings) can be handy to include variables into strings in Javascript. They are invoked by using backticks instead of a single or double quote and they have some "extras":

  • can contain double qotes
  • can contain linie breaks
  • Allow to include Javascript expressions in strings

This is an example:

let name = "Peter"
let text = `His "name" is ${ name }
and he is ${3*5} years old`;
Enter fullscreen mode Exit fullscreen mode

Alternatively you can use string concatenation, which is harder to read:

let name = "Peter"
let text = 'His "name" is '+ name +'\n'+
'and he is '+ (3*5) + ' years old';
Enter fullscreen mode Exit fullscreen mode

In many cases, convenience comes at a price. C-programmers could avoid string concatenation by using sprintf(), but this was know to be fairly slow. So, how do template literals perform?

Performance test

I made a litte test using both approaches side by side in chrome. The inner loop performs 1 Mio string operations each:

    for (let i=0; i<10; i++){
    let t1 = performance.now();

    for (let i = 0; i < 1000000; i++)
        s = "Nr. "+i+" test"  // concatenation

    let t2 = performance.now()
    for (let i = 0; i < 1000000; i++)
        t = `Nr. ${i} test`    // template literals

    let t3 = performance.now()
    document.body.appendChild(div("Time 1-2 was " + (t2 - t1).toFixed() + "ms, Time 2-3 was " + (t3 - t2).toFixed()+"ms"))
      a += t2-t1
      b += t3-t2
  }
  document.body.appendChild(hr())
  document.body.appendChild(div("average: Time 1-2 was " + (a/10).toFixed() + "ms, Time 2-3 was " + (b/10).toFixed()+"ms"))
Enter fullscreen mode Exit fullscreen mode

I used the performance API of chrome and VanJS to create the output, and here is the result:

Time 1-2 was 256ms, Time 2-3 was 168ms
Time 1-2 was 162ms, Time 2-3 was 151ms
Time 1-2 was 143ms, Time 2-3 was 147ms
Time 1-2 was 141ms, Time 2-3 was 144ms
Time 1-2 was 147ms, Time 2-3 was 146ms
Time 1-2 was 142ms, Time 2-3 was 147ms
Time 1-2 was 145ms, Time 2-3 was 143ms
Time 1-2 was 146ms, Time 2-3 was 154ms
Time 1-2 was 145ms, Time 2-3 was 142ms
Time 1-2 was 144ms, Time 2-3 was 143ms
---------------------------------------------------------
average: Time 1-2 was 157ms, Time 2-3 was 148ms
Enter fullscreen mode Exit fullscreen mode

Interestingly, the first loops are a bit slower, but after some rounds the values are about the same. So both ways perform identically, you can choose what fit´s best without any performance leaks.

The code above contains more than just the string concatenation in each loop. So, to see just the performance of one operation, I changed the code and calculated the difference:

for (let i = 0; i < 1000000; i++) {
  s = "Nr. " + i + " test" + i + " test"
}

for (let i = 0; i < 1000000; i++) {
  t = `Nr. ${i} test ${i} test`
}
Enter fullscreen mode Exit fullscreen mode

Now, the time increases from 150 ms to about 200 ms for 1 Mio operations, so one concatenation takes 0,05 Microseconds. This is identical for both approaches.

Anyway, the performance is increadibly. You can perform about 20 Mio string operations per second in the browser. This was measured on my fairly old laptop, which might be outperformed by a factor of 5-10 on a newer machine.

Are they cheating?

I wanted to see, if there are any optimizations working, which could give me wrong results. A compiler would know, that the result of the string operation is not used, so the whole operation or part of it could be skipped. Then we would only see the time of the loop. So, I changed the code a bit to prevent any optimization:

        s += `Nr. ${i} test`    // template literals
Enter fullscreen mode Exit fullscreen mode

Now, the string grows with every operation, giving you a fairly long string of some MB after the loop. This was the result:

Time 1-2 was 1065ms, Time 2-3 was 1462ms
Time 1-2 was 793ms, Time 2-3 was 817ms
Time 1-2 was 823ms, Time 2-3 was 825ms
Time 1-2 was 2793ms, Time 2-3 was 1126ms
Time 1-2 was 856ms, Time 2-3 was 801ms
Time 1-2 was 770ms, Time 2-3 was 786ms
Time 1-2 was 800ms, Time 2-3 was 803ms
Time 1-2 was 798ms, Time 2-3 was 798ms
Time 1-2 was 824ms, Time 2-3 was 788ms
Time 1-2 was 814ms, Time 2-3 was 813ms
-----------------------------------------------------
average: Time 1-2 was 1033ms, Time 2-3 was 902ms
Enter fullscreen mode Exit fullscreen mode

Again, results are identical for both approaches, but the string addition took a lot of time, more than the initial operation took. While the addition of one variable took 0.05 Microseconds, the string addition of the complete string was about 0.65 Microseconds.

I used separate string variables for template literal and concatenation, but did not delete the string after each loop, so, the string grows to a number of 10 Mio additions of "Nr. xxx test", which should be about 120 Mio characters. As you can see, the growing size of the string does not matter for the speed.

Final verdict

Again we can see: Modern Browsers are absolute increadible machines that can be used as a programming platform for a great number of applications. They include a large number of useful API´s to solve a wide range of tasks, so it is worth to try.

Top comments (4)

Collapse
 
artydev profile image
artydev

Largely better than concatenation :-)
Thanks Eckehard

Collapse
 
efpage profile image
Eckehard

We could also create DOM elements using template literals, performance seems to be pretty ok. What do you think about this approach?

    // create element from innerHTML
    function html(s) {
      let d = div()
      d.innerHTML = s
      return d.firstChild
    }

   let el = html("<h1>This is a headline</h1>")
Enter fullscreen mode Exit fullscreen mode
Collapse
 
artydev profile image
artydev

Passing a string like this doesn't allow multilines input, and miss syntax highlighting in some editors.
I tend to use :

html`<h1>This is a headline</h1>`
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
efpage profile image
Eckehard • Edited

Thank you for the reminder. Using template literals is also the basis to use the ${...} syntax for concatenation.

The html-function above gives us some overhead. We have to create an empty element, apply innerHTML, let the DOM render the child and then return the child element. But amazingly, creating the DOM from template literals ist even slightly faster than calling createElement(). Speed difference is not much and in any case not relevant.

You can create more than 100.000 DOM elements per second on an average laptop, so a typical DOM tree may be created within some milliseconds. Usually the browser tries to wait, until the DOM is stable and all images alre loaded before displaying the page.

So, building the DOM is in any case much faster than displaying it.