#58 ✓resolved
Yesudeep Mangalapilly

Fixed: String.prototype.trim() is slow.

Reported by Yesudeep Mangalapilly | August 2nd, 2009 @ 11:28 PM | in 1.3.1 Release

The regular expression-based String.prototype.trim()
implementation is known to be extremely slow.
jQuery uses the same regular expression for its
implementation. I figured this when I was writing a
livesearch plugin that filters through li' elements<br/> and trims each one of them when build indexes.

Benchmarks:

Calling both the implementations 200 times on a string of
length 27662 characters that contains 6 space characters
at the ends resulted in this timing:

trim_regexp: 96ms (27656 characters)
trim_new: 0ms (27656 characters)

Calling the same regexp routine on the same string
100000 times crashed the browser. The newer implementation
uses plain-old loops instead.

I have included the fix for everybody to benefit from
in my fork at http://github.com/yesudeep/rightjs-core/tree
Code is under compatible MIT license.

Here is to hoping rightjs becomes one of the fastest JavaScript
library out there.

Cheers,
Yesudeep.

Comments and changes to this ticket

  • MadRabbit

    MadRabbit August 2nd, 2009 @ 11:44 PM

    Hey Yesudeep,

    thank for your enquiry! there actually other people were pointing me at the issue and there is a little bit more compact version of the method

    function trim (str) {

    var str = str.replace(/^\s\s*/, ''),
        ws = /\s/,
        i = str.length;
    while (ws.test(str.charAt(--i)));
    return str.slice(0, i + 1);
    

    }

    Could you please check it against your test and compare the performance?

  • MadRabbit

    MadRabbit August 3rd, 2009 @ 01:23 AM

    Looked through your article, pretty interesting and looks good, but it seems to me like it doesn't worth of it to include it to the core. I'm more positive about Steve's trim12, it's small, clean and fast enough.

    If you really need this superspeed you always can swap the method on fly in your application, 99.9% of usual users just don't need it and this thing won't make any performance changes in their work.

    Hope you understand

  • Yesudeep Mangalapilly

    Yesudeep Mangalapilly August 3rd, 2009 @ 03:05 AM

    I can understand that, except I'd side with including the most time-efficient function
    that's available, simply because as a user of a library, I'd want to include as less
    of custom code as possible. Sure, I could simply swap in another implementation to override trim(),
    for example. However, that would defeat the purpose of including a library that already has one defined,
    plus we'd have to repeat that for every project me and my team work on. For a user like me
    that would mean more things to maintain when they could easily have been included in a library
    like rightjs.

    Take this example:

    I've written a library that indexes a list of items and then allows keyword searches
    to filter through them. We actually do use such a library for presenting an administrative
    section for client Websites. trim is used heavily to clean up unwanted spaces. Now for every page
    of the administrative section, I end up including:

    1. rightjs
    2. my trim override
    3. the indexer and search script
    4. other scripts

    For me as a programmer, I'd honestly want to remove 2 or any redundant script.
    When I'm filtering through 200 unique items, a regular expression based implementation simply
    takes too much time.

    Now, I understand, you may want to include something that is even smaller and cleaner, but trim
    is a really boring function that gets used a lot. Doesn't hurt to have the fastest one around.

    Anyway, I'll leave it up to you. Oh, and I'll surely benchmark the implementation you've posted
    and report back.

  • Yesudeep Mangalapilly

    Yesudeep Mangalapilly August 3rd, 2009 @ 03:17 AM

    Here are the results:

    Original length: 27662
    trim10: 13ms (length: 27656)
    trim11: 128ms (length: 27656)
    trim12: 95ms (length: 27656)
    trim13: 7ms (length: 27656)
    trim14: 4ms (length: 27656)
    trim15: 3ms (length: 27656)
    trim16: 4ms (length: 27656)
    trim17: 3ms (length: 27656)
    trim18: 762ms (length: 27656)
    trim19: 93ms (length: 27656)

    trim19 is your implementation. Hope that helps. :-)

  • Yesudeep Mangalapilly

    Yesudeep Mangalapilly August 3rd, 2009 @ 03:23 AM

    Oh and that's for 2000 iterations. trim17 is the one I've written.

  • Yesudeep Mangalapilly

    Yesudeep Mangalapilly August 3rd, 2009 @ 03:43 AM

    Also, if you wanted to pick something, I'd probably suggest trim13
    which seems like it has consistent and quick performance across all the browsers.
    Mine seems to run noticeably slower in mozilla browsers.

  • Yesudeep Mangalapilly

    Yesudeep Mangalapilly August 3rd, 2009 @ 05:22 AM

    Have updated the article comments with benchmarks on quite a few browsers
    and platforms. Please see that.

  • MadRabbit

    MadRabbit August 3rd, 2009 @ 10:32 AM

    Tell you what.

    I quite like how you have optimized the thing, pretty smart. No, please, don't think like I'm trying to sweet you before saying "no". Well, I will say you "no" but I do have an idea that might be interesting for you.

    I'll just try to explain myself. With RightJS the speed is not the main goal, the more important thing to me is its compactness and cleanness and pragmatic sense for everyday tasks and usual users. For this reason I don't include in the core fancy stuff that might be useful just once in a while. I'm just trying to build a small and neat core.

    This is all interesting by I had promised you an idea, and here is the thing.

    Some time ago I had started a side project for rightjs; rightjs-goods, where I'm intended to put code like yours, things that might be useful in cases of complex javascript development but not necessary for other 99% people. Things like additional language features, additional visual effects, json support, drag n drop, etc. Modules from the project will be available as standalone files and as options for the custom build process.

    So I'd suggest, I include mine small version in the core, and we include the trim13 (or your version if you'll make it work fast on Firefox), we include it in the goods project.

    What do you think?

  • Yesudeep Mangalapilly

    Yesudeep Mangalapilly August 5th, 2009 @ 01:06 AM

    I actually think that is a good idea but has its own share of problems.
    Firefox 3.5 introduces JavaScript 1.8.1 and with it arrives a
    native implementation of String.prototype.trim() which is faster than
    anything I have seen so far implemented in JavaScript. As a user, I'd
    like to use the fastest version available, so after I have included
    rightjs-core, rightjs-goods does not get a chance to know whether
    String.prototype.trim() was defined natively or previously. I can think
    of two ways around it at the moment.

    1. Set up a flag in or before rightjs-core that indicates the availability of a
      native or previous implementation and let rightjs-goods override accordingly.
      But this is really hackish stuff that seems outright unnecessary.

    2. I maintain a fork of rightjs-core that contains a conditional implementation
      of trim() and a few other methods, so I get what I need, and rightjs-core proper
      still contains clearer code that existing rightjs users can use.

    I think both of us will be happy with the latter approach.

    Also, by the way, I've tested many routines and the latter half of the set of
    routines tested (including mine and excluding the jQuery implementation)
    are consistently faster on all major browsers and platforms. trim17 is only
    marginally slower on Firefox 3.5, but blazes with the latest nightly 3.6a1pre.
    Performance of all trim implementations suffered heavily in the Windows version
    of Firefox.

    The blog post has been updated with charts to show average performance of these
    routines across browsers and I think your version trim19 is a better implementation
    than what already exists in rightjs, so you may go right ahead and include that
    into core.

  • Yesudeep Mangalapilly

    Yesudeep Mangalapilly August 5th, 2009 @ 01:11 AM

    Also I forgot to mention.

    In all the tests I ran so far, trim17 performed fastest in all WebKit based browsers
    with trim16 tailing it. And I still think trim17 can be made even faster. Back to my quest!

    Thanks dude.

  • MadRabbit

    MadRabbit August 5th, 2009 @ 09:17 AM

    Oh, that's cool that FF has it's native method now. I'll do some adjustments then and it will use the method if available.

  • MadRabbit

    MadRabbit August 5th, 2009 @ 10:26 AM

    • Milestone set to 1.3.1 Release

    [milestone:id#46860 bulk edit command]

  • MadRabbit

    MadRabbit August 6th, 2009 @ 11:17 AM

    • State changed from “new” to “resolved”
  • Yesudeep Mangalapilly

    Yesudeep Mangalapilly August 6th, 2009 @ 03:39 PM

    Pretty smart I'd say. I liked this part especially.
    String.prototype.trim.toString().include('return'))

    There's always something to learn from your code.
    I'm not too sure about this though:

    String.WSPS = {};

    Sparse array look-ups will probably turn out to be faster
    since arrays tend to be heavily optimized by browsers and
    may not require calculating hashes for keys. IE is notorious for
    its object look-up implementation. Older JScript implementations
    were known to use linear search instead of real hash-tables for
    objects, so this may come into play as well. I'd avoid using this
    but I'll probably benchmark this as well and let you know.

  • MadRabbit

    MadRabbit August 6th, 2009 @ 03:44 PM

    Ooops. You are right, my bad. Will replace it

Please Sign in or create a free account to add a new ticket.

With your very own profile, you can contribute to projects, track your activity, watch tickets, receive and update tickets through your email and much more.

New-ticket Create new ticket

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile ยป

RightJS Core Tickets

Shared Ticket Bins

People watching this ticket

Pages