Open Bug 1266140 Opened 6 years ago Updated 4 months ago

Object.keys 50% slower than for...in

Categories

(Core :: JavaScript Engine, defect)

defect
Not set
normal

Tracking

()

UNCONFIRMED
Performance P3
Webcompat Priority P3

People

(Reporter: leeoniya, Unassigned)

References

Details

User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:48.0) Gecko/20100101 Firefox/48.0
Build ID: 20160419030312

Steps to reproduce:

Chrome, Edge, IE11 and IE10 perform the following benchmarks in approx the same time (or faster for Object.keys versions), while Firefox is 60% slower:

// single-hash
var hash = {}, key;
for (var i = 0, len = 1e6; i < len; i++) {
	key = Math.random().toString(36).substring(4);
	hash[key] = true;
}

var x;

console.time("for-in");
for (var i in hash)
	x = hash[i];
console.timeEnd("for-in");


console.time("for/keys");
for (var i = 0, keys = Object.keys(hash), len = keys.length; i < len; i++)
	x = hash[keys[i]];
console.timeEnd("for/keys");


// multi-hash
var len = 1e3, hashes = Array(len), key;
for (var j = 0; j < len; j++) {
	var hash = {};
	for (var i = 0; i < len; i++) {
		key = Math.random().toString(36).substring(4);
		hash[key] = true;
	}
	hashes[j] = hash;
}

console.time("for-in (multi)");
for (var j = 0; j < len; j++) {
	hash = hashes[j];
	for (var i in hash)
		x = hash[i];
}
console.timeEnd("for-in (multi)");


console.time("for/keys (multi)");
for (var j = 0; j < len; j++) {
	hash = hashes[j];
	for (var i = 0, keys = Object.keys(hash), len = keys.length; i < len; i++)
		x = hash[keys[i]];
}
console.timeEnd("for/keys (multi)");


Actual results:

50% perf drop.


Expected results:

Faster or same perf.
I came across this bug as I was working on a small JS script to create fractals.
I may be wrong but my suspicion is that the performance has less to do with Object.keys and more to do with how for loops are treated by Spidermonkey.
Consider the following script:

---------------------------------------------------------
var a,b;
randomArray = (length, max) => [...new Array(length)]
              .map(() => Math.round(Math.random() * max));

var test = randomArray(1000000, 10000);

console.time('oldfor'); 
for (var i = 0 ; i < test.length; i++) { b = test[i]; }
console.timeEnd('oldfor'); 

console.time('newfor'); 
for (var t in test) { a = test[t];} 
console.timeEnd('newfor');
---------------------------------------------------------

On Edge, this produces:

oldfor: 463.17ms
newfor: 494.23ms

On Firefox, this produces:

oldfor: 826.65ms
newfor: 652.41ms


It's entirely possible that Object.keys accentuates this difference, but I couldn't be sure. I'll play around a little more tomorrow.
Whiteboard: [qf]
Whiteboard: [qf] → [qf:p3:fx67]

This creates a webcompat issue on mobile where the performance kills the experience. At the origin there is a coding mistake from the web developer of the site but Chrome gets away with it and Firefox freezes.
This is the profile https://share.firefox.dev/3G4i5pD

Webcompat Priority: --- → P3
Performance: --- → P3
Whiteboard: [qf:p3:fx67]
You need to log in before you can comment on or make changes to this bug.