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

UNCONFIRMED
Unassigned

Status

()

UNCONFIRMED
3 years ago
3 months ago

People

(Reporter: leeoniya, Unassigned)

Tracking

Trunk
Points:
---

Firefox Tracking Flags

(Not tracked)

Details

(Whiteboard: [qf:p3:fx67])

(Reporter)

Description

3 years ago
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.

Comment 1

a year ago
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]

Updated

3 months ago
Whiteboard: [qf] → [qf:p3:fx67]
You need to log in before you can comment on or make changes to this bug.