JavaScript string building benchmarks

From Trephine

Jump to: navigation, search
« Efficient JavaScript string building JavaScript task chaining »

[subscribe] Recent blog entries

Live Demos

JavaScript string building benchmarks

Many readers pointed out (correctly) that my exposition on efficient JavaScript string building was in need of benchmarking numbers to be of real value. This article provides those number for several browsers, along with a simple test suite you can try yourself.

Tip: To run the suite yourself, see the String builder benchmark test.

Running the benchmark suite produces a table with the following four columns:

column name description
implementation Description of which implementation is being tested
small (ms) Number of milliseconds it takes to execute the selected implementation, passing in 128 arguments of 128 elements each (16,384 total items)
medium (ms) Number of milliseconds it takes to execute the implementation, passing in passing in 256 arguments of 256 elements each (65,536 total items)
large (ms) Number of milliseconds it takes to execute the implementation, passing in passing in 512 arguments of 512 elements each (262,144 total items)

The implementations can roughly be described as follows:

  1. string buffer - Repeatedly appends to a string variable used as a buffer.
  2. push array buffer - Uses push() to append items to an array buffer.
  3. native assignment - Uses buf[buf.length] to append items to an array.
  4. direct join - Uses join() on each input list, then joins the results.
  5. pre-count buffer - Counts exactly how many items there are in total, then allocates a buffer array of that length.

Here are some results gathered from my Ubuntu 8.04 machine, starting with the fastest and working backwards.

Please note that this is not intended to be an exhaustive set of all browsers, just those that I had readily available at the time of this writing. I plan to provide more stats for more platforms and browsers. In the mean time, the benchmark suite is available if you'd like to collect your own data.

Firefox 3

Firefox 3 is by far the fastest browser I've tested. As you can see, even for the large data set, all times are sub-second:

implementation small (ms) medium (ms) large (ms)
1. string buffer 20.8 126.2 417.6
2. push array buffer 22.2 87.6 807
3. native assignment 22.2 137.2 625.4
4. direct join 10.2 51.8 344.6
5. pre-count buffer 21.8 93.8 288.8

Interesting things to note:

  • Both the push array buffer implementation and the native assignment implementation are significantly slower than the string buffer method.
  • Native assignment is faster than using push().
  • Direct join is significantly faster than all other implementations except the pre-count buffer for the large data set.

Flock 1.2.7 (Firefox 2)

Flock 1.2, which I use in place of a canonical install of Firefox 2, was the next best performing browser I tested:

implementation small (ms) medium (ms) large (ms)
1. string buffer 75 273.4 1240.8
2. push array buffer 107.2 457.4 2033.6
3. native assignment 90.8 451.4 1983.6
4. direct join 18.8 103.6 373
5. pre-count buffer 25.4 169 660.8

Interesting things to note:

  • Both the push array buffer implementation and the native assignment implementation are significantly slower than the string buffer method.
  • Native assignment is faster than using push().
  • Direct join is significantly faster than all other implementations, followed by the pre-count buffer.

Opera 9.2

Opera 9 performed significantly worse than either of the previous two browsers:

implementation small (ms) medium (ms) large (ms)
1. string buffer 87 224.4 13503.8
2. push array buffer 55 287.6 9599.2
3. native assignment 52.6 284.6 9460.6
4. direct join 29.8 158.4 640
5. pre-count buffer 35.2 158.8 595.8

Interesting things to note:

  • Unlike the Firefox derivatives, in Opera the string buffer implementation is the slowest over all.
  • Native assignment is (again) faster than using push().
  • Direct join and pre-count buffer both perform well compared to the other methods.

Internet Explorer 6

Internet Explorer 6 (via wine) is by far the slowest browser I've tested so far. In fact, it was so slow at performing the string buffer benchmark, I had to skip it for the regular sized data sets:

implementation small (ms) medium (ms) large (ms)
1. string buffer -- -- --
2. push array buffer 1190.2 5671.2 39931
3. native assignment 1173.4 5685.6 41460.2
4. direct join 537.8 2079.2 4680
5. pre-count buffer 95 380.4 1395

By paring down the three data set sizes, I was able to get IE 6 to at least complete a string buffer test:

implementation 16x16 (ms) 32x32 (ms) 64x64 (ms)
1. string buffer 70.8 1041 14483.2
2. push array buffer 9 28.4 115.4
3. native assignment 7.8 32.8 99.2
4. direct join 2.6 9.8 41.4
5. pre-count buffer 3.2 6.2 24.2

Interesting things to note:

  • The string buffer method is orders of magnitude slower than all other methods.
  • The push array buffer and native assignment methods perform similarly and are both significantly slower than direct join and pre-count buffer.
  • The pre-count buffer method is by far the fastest, especially so for larger data sets.

Conclusions

At the time of this writing, IE 6 on Windows has about 20% global market share. Given that the speed differences between implementations in Firefox are small in comparison to IE's differences, and IE 6 still captures a non-negligible portion of the market, I feel the prudent thing to do is to stick with the guidelines established at the end of efficient JavaScript string building.

Hope this helps, thanks for reading!

--Jim R. Wilson (jimbojw) 08:29, 1 May 2009 (UTC)
Personal tools