Click here to Skip to main content
Click here to Skip to main content

JavaScript StringBuilder

By , 6 Dec 2005
 

Introduction

Once upon a time, not so long ago, pushing any significant processing to the client browser was considered a bad practice. Now with the rise in popularity of AJAX style development, it has suddenly become a hot new technology. Unfortunately, the most commonly used browser on the market is painfully slow at one of the most common tasks in programming -- string concatenation.

The good news is that although IE is slow when it comes to string concatenation, it is quite fast with array operations. With this in mind, I decided to write a simple StringBuilder class that pushes individual strings into an array and then uses the join method to produce the concatenated output string. In tests I have run with 5,000 strings, it is 117 times faster than the equivalent string concatenation using the s1 += s2 syntax. With 10,000 strings, it is an amazing 261 times faster!

Using the code

The StringBuilder class only provides four methods: a constructor, an append method, a clear method, and a toString method. You can add more properties and methods if you need them, but I chose to keep it as simple as possible for this article.

Here is the entire script that defines the StringBuilder class:

// Initializes a new instance of the StringBuilder class
// and appends the given value if supplied
function StringBuilder(value)
{
    this.strings = new Array("");
    this.append(value);
}

// Appends the given value to the end of this instance.
StringBuilder.prototype.append = function (value)
{
    if (value)
    {
        this.strings.push(value);
    }
}

// Clears the string buffer
StringBuilder.prototype.clear = function ()
{
    this.strings.length = 1;
}

// Converts this instance to a String.
StringBuilder.prototype.toString = function ()
{
    return this.strings.join("");
}

The code is so simple and straightforward that it should be self-explanatory. Now here's an example of how to use it:

// create a StringBuilder
var sb = new StringBuilder();

// append some text
sb.append("Lorem ipsum dolor sit amet, consectetuer adipiscing elit, ");
sb.append("sed diem nonummy nibh euismod tincidunt ut lacreet dolore ");
sb.append("magna aliguam erat volutpat.");

// get the full string value
var s = sb.toString();

Again, so simple and straightforward it shouldn't require any further explanation. If you've ever used the StringBuilder in .NET, then you already know how to use this one.

If you download the demo project, you will find an HTML page that performs a side-by-side comparison of StringBuilder vs. string concatenation. You can use it to run your own tests to see the difference for yourself. On my machine, it takes IE over 14 seconds to concatenate 5,000 strings. The StringBuilder does it in 110 ms. With 10,000 strings, it takes IE a full minute to concatenate. The StringBuilder does it in 230 ms. More than a minute to less than a quarter of a second, that's a fairly significant improvement!

Conclusion

The whole purpose of pushing processing to the client is to provide a richer, more responsive user experience. That means, it's important to make sure the client-side code is as efficient as possible. I hope this article helps your client-side string building code really scream.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

K.Collins
Architect Epsilon
United States United States
Member
IT professional with fifteen years experience designing and building software and web applications for local, national, and global organizations in a variety of industries including telecommunications, insurance, accounting, finance, not-for-profit, marketing, payment services, loyalty services, e-commerce, and e-business.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralNot working in FireFox, Chrome and Safari, and runs slower on IE and Operamemberynnorj2 Dec '09 - 18:05 
IE8 results:
String concat test complete. Total process time 8 ms.
StringBuilder test complete. Total process time 33 ms.
 
Opera results:
String concat test complete. Total process time 32 ms.
StringBuilder test complete. Total process time 38 ms.
 
Other's:
Running tests...
GeneralRe: Not working in FireFox, Chrome and Safari, and runs slower on IE and OperamemberErikerikerikerikerassa2 Jan '10 - 13:30 
Resave the files with correct encoding to run in Firefox.
Anyway this is not faster than concat in FF or IE8.
 
FF 3.5:
String concat test complete. Total process time 25 ms.
StringBuilder test complete. Total process time 24 ms.
 
IE8:
String concat test complete. Total process time 0 ms.
StringBuilder test complete. Total process time 31 ms
Also note that the minimum timestep in IE seems to be 31ms so to make more accurate tests on new computers, more than 5000 items has to be used in the test.
 
The pattern is the same though, with 60K items in IE8
String concat test complete. Total process time 125 ms.
StringBuilder test complete. Total process time 484 ms.
and FF
String concat test complete. Total process time 462 ms.
StringBuilder test complete. Total process time 425 ms.
GeneralRe: Not working in FireFox, Chrome and Safari, and runs slower on IE and OperagroupKikoz6814 Jul '11 - 10:11 
Use this one
QuestionStringBuilderPlus & Length = 1?memberaspdotnetdev7 Sep '09 - 21:32 
First, I have a suggestion:
Also, while I'm here, I figure I'll ask a question as well
  • I'm no JavaScript expert, but won't the following code (from your article) leave 1 string in the strings array (when it should probably be emptying it entirely)?
    // Clears the string buffer
    StringBuilder.prototype.clear = function ()
    {
        this.strings.length = 1;
    }
 
By the way, good idea... the lack of a StringBuilder in a language so closely tied to strings seems absurd. Great addition!
 
Visual Studio is an excellent GUIIDE.

AnswerRe: StringBuilderPlus & Length = 1?memberK.Collins8 Sep '09 - 5:38 
Adding support for prefixing and nesting is a good idea. Thanks for the suggestion.
 
I initialize the strings array with 1 empty string. Then I set the length back to 1 in the clear method which leaves the original empty string. I wanted to avoid any possible issues with calling the join method on an empty array.
 
Thanks for the question.
GeneralIt is amazingmemberarijit00729 Jan '09 - 0:39 
You dont know how much this article helped me.
It is really fastest
GeneralRe: It is amazingmemberK.Collins29 Jan '09 - 5:04 
I'm glad it helped. Thanks.
GeneralCode Update (by player's edited version)memberplayer.7 Oct '08 - 20:20 
Add function : StringBuilder.prototype.appendFormat
 
http://www.player.idv.tw/prog/index.php?title=JavaScript:StringBuilder[^]
 

Ex: Test
<script type="text/javascript" src="StringBuilder.js"></script>
 
<script type="text/javascript">
var sb = new StringBuilder();
 
//Test appendFormat
sb.appendFormat("{0} + {1} = {2}", "A", "B", "C");
 
// get the full string value
var s = sb.toString();
alert(s); 
</script>

 
Taiwan's pauper.

GeneralRe: Code Update (by player's edited version)memberK.Collins8 Oct '08 - 4:16 
An appendFormat method would be a valuable addition. I also like the way you have added return this; to the append method so that you can string multiple calls together. These are both excellent contributions. Thanks.
GeneralRe: Code Update (by player's edited version)memberplayer.29 Jul '09 - 21:55 
Add function : StringBuilder.prototype.appendPrintf
 
http://www.player.idv.tw/prog/index.php?title=JavaScript:StringBuilder[^]
 
ref sprintf
http://jan.moesen.nu/code/javascript/sprintf-and-printf-in-javascript/[^]
and http://plugins.jquery.com/project/printf[^]
 
Ex: Test
// create a StringBuilder
var sb = new StringBuilder();
 
sb.appendPrintf("'30' -> decimal: %d / bin = %b / oct = %o / hex = %x / HEX = %X ....", 30, 30, 30, 30, 30);
 
 
// get the full string value
var s = sb.toString();       
alert(s);

 
Taiwan's pauper.

GeneralGoogle Chrome resultsmemberIgor Glasner23 Sep '08 - 7:48 
String concat test complete. Total process time 6 ms.
StringBuilder test complete. Total process time 35 ms.
 
By far, the fastest browser! Of course it is fast - it compiles javascript into assembly language. However, with Google Chrome it is counterproductive to use StringBuilder wrapper, because it handles string concatenations well.
 
Cheers!
 

GeneralRe: Google Chrome resultsmemberK.Collins8 Oct '08 - 4:09 
Very interesting. I'm pleased to see that Chrome handles string concatenations so well. I'm a little surprised that it is actually slower with array operations though. Thanks for sharing these results.
GeneralThank you.memberarockj11 Jun '08 - 13:36 
I love it. Thank so much!
GeneralRe: Thank you.memberK.Collins12 Jun '08 - 5:53 
You're welcome. I'm glad to know that I've contributed something that others find useful.
GeneralEven Faster...memberLTSpeed21 Jun '07 - 3:46 
I think this may be even faster.   It combines every optimization technique I could find on the web and is cross-browser.
 
function FastString(str,n) {
     var s = [];
     var i = n%8;
     if (i>0) {
          do {
               s[s.length] = str;
          } while (--i);
     }
     var n = parseInt(n/8);
     do {
          s[s.length] = str;
          s[s.length] = str;
          s[s.length] = str;
          s[s.length] = str;
          s[s.length] = str;
          s[s.length] = str;
          s[s.length] = str;
          s[s.length] = str;
     } while (--n);
     return s.join("");
}
GeneralThanksmemberSuperDuckZA_PS8 Apr '07 - 4:17 
Thanks - this really helped me today.
 
JS
GeneralRe: ThanksmemberK.Collins9 Apr '07 - 4:34 
Glad you found it useful.
GeneralVery Good idea, with a small change!memberAjaxDino18 Jan '07 - 14:50 
Thanks for the brilliant idea, so easy, simple and useful.
 
One small change that will make it behave like a real Java StringBuffer is to be able to chain append(..) in one go, like
 
var sb = new StringBuilder();
sb.append('My name is').append(' John Smith ').append(' and I am ').append(35).append( 'years old');
 

All you need to do is to add return this to the end of append(...) function, as:
 

StringBuilder.prototype.append = function (value)
{
if (value)
{
this.strings.push(value);
}

return this; //- add this one to allow the the chain capability
}

 
Thanks
 
Daniel M.
 
------------------------------------------------------------
Chaos Doesn't create Equilibirum
GeneralRe: Very Good idea, with a small change!memberK.Collins19 Jan '07 - 4:52 
Great suggestion! Why didn't I think of that? D'Oh! | :doh:
QuestionDoesn't work in Firefox?memberjswoofer17 Sep '06 - 16:55 
I downloaded and opened the demo "StringBuilder.htm" in Firefox. After clicking the button, nothing happens. I can't see any immediate problems. Does anyone know what the problem could be? Thanks.

AnswerRe: Doesn't work in Firefox?memberAndrei Bozantan22 Sep '06 - 7:36 
The encoding of the StringBuilder.js file is ANSI, try to change it to UTF 8. You can do this by using a tool like Notepad++. Anyway, if your target is firefox it doesn't worth the effort, because the results are almost the same in both cases.
Use Opera 9, it's the fastest.
QuestionIs it from Atlas?memberabakar12 Dec '05 - 17:32 
I've found this class in AtlasRuntime.js

AnswerRe: Is it from Atlas?memberK.Collins13 Dec '05 - 4:00 
I did not get it from Atlas. I've heard of Atlas, but I haven't had a chance to check it out yet.
 
Is their class exactly like mine?
GeneralRe: Is it from Atlas?memberabakar13 Dec '05 - 17:27 

 
Ideas in the air.
Web.StringBuilder = function(initialText)
{
    var _parts = new Array();
    
    if ((typeof(initialText) == 'string') && (initialText.length != 0))
    {
        parts.add(initialText);
    }
 
    this.append = function(text)
    {
        if ((text == null)||(typeof(text) == 'undefined'))
        {
            return;
        }
 
        if ((typeof(text) == 'string')&&(text.length == 0))
        {
            return;
        }
 
        _parts.add(text);
    }
 
    this.toString = function(delimiter)
    {
        delimiter = delimiter || '';
        return _parts.join(delimiter);
    }
}
 
Type.registerSealedClass('Web.StringBuilder');

GeneralCross Browser CompatibiltymemberDavy Boy12 Dec '05 - 3:39 
The demo project I tried to run straight out of the box, under FireFox 1.5, (Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8) Gecko/20051111 Firefox/1.5), and I get JavaScript errors.
 
However, dumping the script into the same HTML, it works fine.
 
On side notes...
 
IE, 10:1 speed increase
Opera: 31ms (concat):78ms(SB)
FF(1.5): ~900ms(concat):~1000ms(SB).
 

So I guess it is a case of do you target the majority audience, or do you appreciate the growing minority, and appreciate the slow down this method causes. Still, a fantastic effort nevertheless.
 
Davy Boy Out...

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130523.1 | Last Updated 6 Dec 2005
Article Copyright 2005 by K.Collins
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid