Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

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

#58

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.

Reported by Yesudeep Mangalapilly · August 2nd, 2009 @ 11:28 PM

State: resolved
Milestone: 1.3.1 Release
Assigned to: MadRabbit MadRabbit

Activity

  1. MadRabbit
    MadRabbit

    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?

    August 2nd, 2009 @ 11:44 PM

  2. MadRabbit
    MadRabbit

    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

    August 3rd, 2009 @ 01:23 AM

  3. Yesudeep Mangalapilly
    Yesudeep Mangalapilly

    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.

    August 3rd, 2009 @ 03:05 AM

  4. Yesudeep Mangalapilly
    Yesudeep Mangalapilly

    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. :-)

    August 3rd, 2009 @ 03:17 AM

  5. Yesudeep Mangalapilly
    Yesudeep Mangalapilly

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

    August 3rd, 2009 @ 03:23 AM

  6. Yesudeep Mangalapilly
    Yesudeep Mangalapilly

    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.

    August 3rd, 2009 @ 03:43 AM

  7. Yesudeep Mangalapilly
    Yesudeep Mangalapilly

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

    August 3rd, 2009 @ 05:22 AM

  8. MadRabbit
    MadRabbit

    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?

    August 3rd, 2009 @ 10:32 AM

  9. Yesudeep Mangalapilly
    Yesudeep Mangalapilly

    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.

    August 5th, 2009 @ 01:06 AM

  10. Yesudeep Mangalapilly
    Yesudeep Mangalapilly

    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.

    August 5th, 2009 @ 01:11 AM

  11. MadRabbit
    MadRabbit

    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.

    August 5th, 2009 @ 09:17 AM

  12. MadRabbit
    MadRabbit
    • Milestone set to 1.3.1 Release

    [milestone:id#46860 bulk edit command]

    August 5th, 2009 @ 10:26 AM

  13. MadRabbit
    MadRabbit
    • State changed from new to resolved

    August 6th, 2009 @ 11:17 AM

  14. Yesudeep Mangalapilly
    Yesudeep Mangalapilly

    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.

    August 6th, 2009 @ 03:39 PM

  15. MadRabbit
    MadRabbit

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

    August 6th, 2009 @ 03:44 PM

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.