New issue
Advanced search Search tips

Issue 779148 link

Starred by 3 users

Issue metadata

Status: Fixed
Owner:
Closed: Oct 25
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Linux , Android , Windows , Chrome , Mac , Fuchsia
Pri: 2
Type: Bug



Sign in to add a comment

Speed-up Array.join("")

Reported by ivan.kuc...@gmail.com, Oct 27 2017

Issue description

UserAgent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36

Steps to reproduce the problem:
1. In my work, I often use a "string-builder": I put many strings into an array and then concatenate them by calling arr.join("");
2. Right now, I have a practical case, where I need to concat 40 millions single-character strings.

I made a demo: http://www.ivank.net/veci/join_test.html
It joins 40 millions single-character strings and prints the computation time into the console.

What is the expected behavior?

What went wrong?
In Chrome, it takes 5700 ms, while in Firefox, it takes 360 ms (16x faster).

Could you speed-up joining with an empty string? It is often used in practice as a "string-builder".

Did this work before? N/A 

Chrome version: 62.0.3202.62  Channel: n/a
OS Version: 6.1 (Windows 7, Windows Server 2008 R2)
Flash Version: Shockwave Flash 27.0 r0
 
Components: -Blink Blink>JavaScript

Comment 2 by woxxom@gmail.com, Oct 27 2017

Some related notes:

Array#join is a bit faster in Chrome Canary 64, but still takes more than 3 seconds.

Possible workarounds for this *specific case* that match or even outperform Firefox on the original code:

* store character codes, join in chunks (~350ms, Canary: 200ms)
  var chrs = []; 
  for (var i=0; i<40000000; i++) chrs.push(64+(i&31));

  var strs = [];
  for (var i = 0; i<chrs.length/10e3; i++)
    strs.push(String.fromCharCode.apply(null, chrs.slice(i * 10e3, (i + 1) * 10e3)));
  var str = strs.join('');

* store character codes, use TextDecoder (~100ms)
  var chrs = []; 
  for (var i=0; i<40000000; i++) chrs.push(64+(i&31));
  var str = new TextDecoder().decode(new Uint8Array(chrs));
Wooooow ... Precisely, I am parsing a 40 MB JSON file from an ArrayBuffer. First, I parse UTF8 (convert bytes into Unicode codes - integers), then I call String.fromCharCode on each code. Then I concatenate it with .join(""). Then I can give that string to JSON.parse();

I was so desperate that I wrote my own JSON parser, that works directly with char codes (avoiding a long string). It seems like TextDecoder can save me a lot of work (I never heard about it before). But it is still not supported in Edge :(
Cc: bmeu...@chromium.org jgruber@chromium.org
Labels: OS-Android OS-Chrome OS-Fuchsia OS-iOS OS-Linux OS-Mac
Status: Available (was: Unconfirmed)
For posterity, the demo in #0 is:

				var chrs = [];
				for(var i=0; i<40000000; i++) chrs.push(String.fromCharCode(64+(i&31)));
				
				var time = Date.now();
				var str = chrs.join("");
				console.log(Date.now()-time);
Labels: -OS-iOS
Guys, I think we can close it, since TextDecoder() solves my problem, so I don't need fast string joining anymore.
Cc: peter.wm...@gmail.com
Owner: jgruber@chromium.org
Status: Assigned (was: Available)
FYI the new Array.p.join Torque implementation is currently under review at https://crrev.com/c/1196693.
Status: Fixed (was: Assigned)
Peter's new join impl has landed, this is what I now see locally in d8:

$ out/release/d8 tmp.js 
802

$ cat tmp.js
const chrs = [];
const chr = String.fromCharCode(64+(i&31));
for (var i=0; i<40000000; i++) chrs.push(chr);

const time = Date.now();
const str = chrs.join("");
console.log(Date.now()-time, str.length);

Sign in to add a comment