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 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 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 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:- rightjs
- my trim override
- the indexer and search script
- 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. - rightjs
-
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 August 3rd, 2009 @ 03:23 AM
Oh and that's for 2000 iterations. trim17 is the one I've written.
-
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 August 3rd, 2009 @ 05:22 AM
Have updated the article comments with benchmarks on quite a few browsers
and platforms. Please see that. -
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 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.-
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. -
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 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 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 August 5th, 2009 @ 10:26 AM
- Milestone set to 1.3.1 Release
[milestone:id#46860 bulk edit command]
-
MadRabbit August 6th, 2009 @ 11:17 AM
- State changed from new to resolved
Hey Yesudeep
I've put your code over here
http://github.com/rightjs/rightjs-goods/blob/f4dc2a04eca874f76308a4...
-
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.
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.
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile ยป
RightJS Core Tickets