Why is for-in slow in javascript? - javascript

I have read in several places that for-in loops are slower than looping over an array... Though I understand that moving forward in sizeof (type) blocks is practically effortless compared to whatever happens behind to the scenes to iterate over an object's keys, I am still curious, what the exact reason is that it's so slow...
Is it having to do a reverse hash function to get the key, and that process is what is slow?

The real answer to this in the case of any particular engine will likely depend on that engine's implementation. (As will the size of the difference, if any.)
However, there are invariants. For instance, consider:
var obj = {a: "alpha", b: "beta"};
var name;
for (name in obj) {
console.log(obj[name]);
}
var arr = ["alpha", "beta"];
var index;
for (index = 0; index < arr.length; ++index) {
console.log(arr[index]);
}
In the case of obj, the engine has to use a mechanism to keep track of which properties you've already iterated over and which ones you haven't, as well as filtering out the non-enumerable properties. E.g., there's some kind of iterator object behind the scenes (and the way the spec is defined, that may well be a temporary array).
In the case of arr, it doesn't; you're handling that in your code, in a very simple, efficient way.
The content of the block of each loop is the same: A property lookup on an object. (In the latter case, in theory, there's a number-to-string conversion as well.)
So I expect the only non-implementation-specific answer to this is: Additional overhead.

for..each loops use iterators and generators.
Iterator is an object that has a next() method. Generator is a factory function that contains yield() expressions. Both constructs are more complicated than an integer index variable.
In a typical for(var i = 0; i < arr.length; i++) loop, the two commands that execute in almost all iterations are i++ and i < arr. This is arguably much faster than making a function call (next() or yield()).
Moreover, the loop initiation (var i = 0) is also faster than creating the iterator object with next() method or calling the generator to create the iterator. However, it highly depends on the implementation and the creators of Javascript engines do their best to accelerate such commonly used language features.
I would say the difference is so marginal that I might want to spend my time optimizing other parts of the code. The choice of syntax should consider code readability and maintainability more than performance, when the performance gain is so small for adding complexity. Having said that, use the syntax that makes more sense to you and other developers who maintain your code after you get rich and famous! ;)

Related

Is forEach equivalent exactly to a for loop? [duplicate]

I've seen plenty of questions that suggest using:
for (var i = 0; i < myArray.length; i++){ /* ... */ }
instead of:
for (var i in myArray){ /* ... */ }
for arrays, due to inconsistent iteration (see here).
However, I can't seem to find anything that seems to prefer the object oriented loop:
myArray.forEach(function(item, index){ /* ... */ });
Which seems way more intuitive to me.
For my current project, IE8 compatibilty is important, and I'm considering using Mozilla's polyfill, however I'm not 100% sure how this will work.
Are there any differences between the standard for loop (the first example above) and the Array.prototype.forEach implementation by modern browsers?
Are there any difference between modern browser implementations and Mozilla's implementation linked to above (with special regard to IE8)?
Performance is not as much of an issue, just consistency with which properties are iterated over.
The most substantive difference between the for loop and the forEach method is that, with the former, you may break out of the loop. You can simulate continue by simply returning from the function passed to forEach, but there is no way to stop looping altogether.
Aside from that, the two accomplish effectively the same functionality. Another minor difference involves the scope of the index (and all containing variables) in the for loop, due to variable hoisting.
// 'i' is scoped to the containing function
for (var i = 0; i < arr.length; i++) { ... }
// 'i' is scoped to the internal function
arr.forEach(function (el, i) { ... });
However, I find that forEach is much more expressive—it represents your intent to iterate through each element of an array, and it provides you with a reference to the element, not just the index. Overall, it mostly comes down to personal taste, but if you can use forEach, I would recommend using it.
There are a few more substantial differences between the two versions, specifically regarding performance. In fact, the simple for loop performs considerably better than the forEach method, as demonstrated by this jsperf test.
Whether or not such performance is necessary for you is up to you to decide, and in most cases, I would favor expressiveness over speed. This speed difference is likely due to the minor semantic differences between the basic loop and the method when operating on sparse arrays, as noted in this answer.
If you don't need the behavior of forEach and/or you need to break out of the loop early, you can use Lo-Dash's _.each as an alternative, which will also work cross-browser. If you're using jQuery, it also provides a similar $.each, just note the differences in arguments passed to the callback function in each variation.
(As for the forEach polyfill, it should work in older browsers without problems, if you choose to go that route.)
You can use your custom foreach function which will perform much better then Array.forEach
You should add this once to your code. This will add new function to the Array.
function foreach(fn) {
var arr = this;
var len = arr.length;
for(var i=0; i<len; ++i) {
fn(arr[i], i);
}
}
Object.defineProperty(Array.prototype, 'customForEach', {
enumerable: false,
value: foreach
});
Then you can use it anywhere like the Array.forEach
[1,2,3].customForEach(function(val, i){
});
The only difference it is 3 times faster. https://jsperf.com/native-arr-foreach-vs-custom-foreach
UPDATE: In new Chrome version the performance of .forEach() was improved. However, the solution can give the additional performance in other browsers.
It is suggested by many developers (e.g. Kyle Simpson) to use .forEach to indicate that the array will have a side effect and .map for pure functions. for loops fit well as a general-purpose solution for known number of loops or any other case that doesn't fit as it is easier to communicate because of its broad support across the majority of programming languages.
e.g.
/* For Loop known number of iterations */
const numberOfSeasons = 4;
for (let i = 0; i < numberOfSeasons; i++) {
//Do Something
}
/* Pure transformation */
const arrayToBeUppercased = ['www', 'html', 'js', 'us'];
const acronyms = arrayToBeUppercased.map((el) => el.toUpperCase));
/* Impure, side-effects with .forEach */
const acronymsHolder = [];
['www', 'html', 'js', 'us'].forEach((el) => acronymsHolder.push(el.toUpperCase()));
Convention wise, this seems best, however the community hasn't really settled on a convention on the newer iteration protocol for in loops. Generally, I think it's a good idea to follow the FP concepts that the JS community seems to be open to adopting.

What are the advantages of using forEach vs for? [duplicate]

I've seen plenty of questions that suggest using:
for (var i = 0; i < myArray.length; i++){ /* ... */ }
instead of:
for (var i in myArray){ /* ... */ }
for arrays, due to inconsistent iteration (see here).
However, I can't seem to find anything that seems to prefer the object oriented loop:
myArray.forEach(function(item, index){ /* ... */ });
Which seems way more intuitive to me.
For my current project, IE8 compatibilty is important, and I'm considering using Mozilla's polyfill, however I'm not 100% sure how this will work.
Are there any differences between the standard for loop (the first example above) and the Array.prototype.forEach implementation by modern browsers?
Are there any difference between modern browser implementations and Mozilla's implementation linked to above (with special regard to IE8)?
Performance is not as much of an issue, just consistency with which properties are iterated over.
The most substantive difference between the for loop and the forEach method is that, with the former, you may break out of the loop. You can simulate continue by simply returning from the function passed to forEach, but there is no way to stop looping altogether.
Aside from that, the two accomplish effectively the same functionality. Another minor difference involves the scope of the index (and all containing variables) in the for loop, due to variable hoisting.
// 'i' is scoped to the containing function
for (var i = 0; i < arr.length; i++) { ... }
// 'i' is scoped to the internal function
arr.forEach(function (el, i) { ... });
However, I find that forEach is much more expressive—it represents your intent to iterate through each element of an array, and it provides you with a reference to the element, not just the index. Overall, it mostly comes down to personal taste, but if you can use forEach, I would recommend using it.
There are a few more substantial differences between the two versions, specifically regarding performance. In fact, the simple for loop performs considerably better than the forEach method, as demonstrated by this jsperf test.
Whether or not such performance is necessary for you is up to you to decide, and in most cases, I would favor expressiveness over speed. This speed difference is likely due to the minor semantic differences between the basic loop and the method when operating on sparse arrays, as noted in this answer.
If you don't need the behavior of forEach and/or you need to break out of the loop early, you can use Lo-Dash's _.each as an alternative, which will also work cross-browser. If you're using jQuery, it also provides a similar $.each, just note the differences in arguments passed to the callback function in each variation.
(As for the forEach polyfill, it should work in older browsers without problems, if you choose to go that route.)
You can use your custom foreach function which will perform much better then Array.forEach
You should add this once to your code. This will add new function to the Array.
function foreach(fn) {
var arr = this;
var len = arr.length;
for(var i=0; i<len; ++i) {
fn(arr[i], i);
}
}
Object.defineProperty(Array.prototype, 'customForEach', {
enumerable: false,
value: foreach
});
Then you can use it anywhere like the Array.forEach
[1,2,3].customForEach(function(val, i){
});
The only difference it is 3 times faster. https://jsperf.com/native-arr-foreach-vs-custom-foreach
UPDATE: In new Chrome version the performance of .forEach() was improved. However, the solution can give the additional performance in other browsers.
It is suggested by many developers (e.g. Kyle Simpson) to use .forEach to indicate that the array will have a side effect and .map for pure functions. for loops fit well as a general-purpose solution for known number of loops or any other case that doesn't fit as it is easier to communicate because of its broad support across the majority of programming languages.
e.g.
/* For Loop known number of iterations */
const numberOfSeasons = 4;
for (let i = 0; i < numberOfSeasons; i++) {
//Do Something
}
/* Pure transformation */
const arrayToBeUppercased = ['www', 'html', 'js', 'us'];
const acronyms = arrayToBeUppercased.map((el) => el.toUpperCase));
/* Impure, side-effects with .forEach */
const acronymsHolder = [];
['www', 'html', 'js', 'us'].forEach((el) => acronymsHolder.push(el.toUpperCase()));
Convention wise, this seems best, however the community hasn't really settled on a convention on the newer iteration protocol for in loops. Generally, I think it's a good idea to follow the FP concepts that the JS community seems to be open to adopting.

Javascript For-Loop Condition Caching

I've put together a jsperf test that compares for loops that iterate over an array with caching the array length condition vs not caching. I thought that caching the variable before to avoid recalculating the array length each iteration would be faster, but the jsperf test says otherwise. Can someone explain why this is? I also thought that including the array length variable definition (when cached) within the for loop's initialization would reduce the time since the parse doesn't need to look up the "var" keyword twice, but that also doesn't appear to be the case.
example without caching:
for(var i = 0; i < testArray.length; i++){
//
}
example with caching
var len = testArray.length;
for(var i = 0; i < len; i++){
//
}
example with caching variable defined in for loop initialization
for(var i = 0, len=testArray.length; i < len; i++){
//
}
http://jsperf.com/for-loop-condition-caching
Can someone explain why this is?
This optimization and case is extremely common so modern JavaScript engines will automatically perform this optimization for you.
Some notes:
This is not the case when iterating a NodeList (such as the result of querySelectorAll
This is an overkill micro optimization for most code paths anyway, usually the body of the loop takes more time than this comparison anyway.
The performance of the scenarios that you posted depends on how smart the JS engine's optimizer is. An engine with a very dump optimizer (or no optimizer at all) will likely be faster when you are using the variable, but you can't even rely on that. After all, length's type is well-known, while a variable can be anything and may require additional checks.
Given a perfect optimizer, all three examples should have the same performance. And as your examples are pretty simple, modern engines should reach that point soon.

JavaScript - Nuances of myArray.forEach vs for loop

I've seen plenty of questions that suggest using:
for (var i = 0; i < myArray.length; i++){ /* ... */ }
instead of:
for (var i in myArray){ /* ... */ }
for arrays, due to inconsistent iteration (see here).
However, I can't seem to find anything that seems to prefer the object oriented loop:
myArray.forEach(function(item, index){ /* ... */ });
Which seems way more intuitive to me.
For my current project, IE8 compatibilty is important, and I'm considering using Mozilla's polyfill, however I'm not 100% sure how this will work.
Are there any differences between the standard for loop (the first example above) and the Array.prototype.forEach implementation by modern browsers?
Are there any difference between modern browser implementations and Mozilla's implementation linked to above (with special regard to IE8)?
Performance is not as much of an issue, just consistency with which properties are iterated over.
The most substantive difference between the for loop and the forEach method is that, with the former, you may break out of the loop. You can simulate continue by simply returning from the function passed to forEach, but there is no way to stop looping altogether.
Aside from that, the two accomplish effectively the same functionality. Another minor difference involves the scope of the index (and all containing variables) in the for loop, due to variable hoisting.
// 'i' is scoped to the containing function
for (var i = 0; i < arr.length; i++) { ... }
// 'i' is scoped to the internal function
arr.forEach(function (el, i) { ... });
However, I find that forEach is much more expressive—it represents your intent to iterate through each element of an array, and it provides you with a reference to the element, not just the index. Overall, it mostly comes down to personal taste, but if you can use forEach, I would recommend using it.
There are a few more substantial differences between the two versions, specifically regarding performance. In fact, the simple for loop performs considerably better than the forEach method, as demonstrated by this jsperf test.
Whether or not such performance is necessary for you is up to you to decide, and in most cases, I would favor expressiveness over speed. This speed difference is likely due to the minor semantic differences between the basic loop and the method when operating on sparse arrays, as noted in this answer.
If you don't need the behavior of forEach and/or you need to break out of the loop early, you can use Lo-Dash's _.each as an alternative, which will also work cross-browser. If you're using jQuery, it also provides a similar $.each, just note the differences in arguments passed to the callback function in each variation.
(As for the forEach polyfill, it should work in older browsers without problems, if you choose to go that route.)
You can use your custom foreach function which will perform much better then Array.forEach
You should add this once to your code. This will add new function to the Array.
function foreach(fn) {
var arr = this;
var len = arr.length;
for(var i=0; i<len; ++i) {
fn(arr[i], i);
}
}
Object.defineProperty(Array.prototype, 'customForEach', {
enumerable: false,
value: foreach
});
Then you can use it anywhere like the Array.forEach
[1,2,3].customForEach(function(val, i){
});
The only difference it is 3 times faster. https://jsperf.com/native-arr-foreach-vs-custom-foreach
UPDATE: In new Chrome version the performance of .forEach() was improved. However, the solution can give the additional performance in other browsers.
It is suggested by many developers (e.g. Kyle Simpson) to use .forEach to indicate that the array will have a side effect and .map for pure functions. for loops fit well as a general-purpose solution for known number of loops or any other case that doesn't fit as it is easier to communicate because of its broad support across the majority of programming languages.
e.g.
/* For Loop known number of iterations */
const numberOfSeasons = 4;
for (let i = 0; i < numberOfSeasons; i++) {
//Do Something
}
/* Pure transformation */
const arrayToBeUppercased = ['www', 'html', 'js', 'us'];
const acronyms = arrayToBeUppercased.map((el) => el.toUpperCase));
/* Impure, side-effects with .forEach */
const acronymsHolder = [];
['www', 'html', 'js', 'us'].forEach((el) => acronymsHolder.push(el.toUpperCase()));
Convention wise, this seems best, however the community hasn't really settled on a convention on the newer iteration protocol for in loops. Generally, I think it's a good idea to follow the FP concepts that the JS community seems to be open to adopting.

For Array, is it more efficient to use map() & reduce() instead of forEach() in javascript?

1)As we know, there's no side-effect with map() and reduce(). Nowadays, we also have muti-core on cell phone. So is it more efficient to use them?
2)On the other hand, there's only 1 thread for js to execute on most of the browsers. Therefor map() and reduce() are prepared for server-side scripting?
I just tested this today, using map and reduce over floating point numbers, with the latest node.js version, and the answer is that map and reduce was two orders of magnitude slower than an regular for loop.
var r = array.map(x => x*x).reduce( (total,num) => total+num,0);
~11,000ms
var r = 0.0;
array.forEach( (x,i,a) => r += x*x )
~300ms
var r = 0.0;
for (var j = 0; j < array.length;j++){
var x = array[j];
r += x*x;
}
~35ms
EDIT: One should note that this difference is much less in Firefox, and may be much less in future version of Node / Chrome as well.
1)
there's no side-effect with map() and reduce()
Well. You very well can implement map and reduce callbacks having side effects. Nothing prevents it and in the current state of JavaScript it's not even considered as bad practice.
2)
there's only 1 thread for js to execute on most of the browsers
There's only one thread in all today's JS engines, even when they run server-side (in fact there can be more but in isolation, not accessing the same array).
So the fact there is no side effect wouldn't make array modifications parallelisable at all. No JS engine can do otherwise than call the callback sequentially on standard arrays.
Note : as pointed by zirak, there's this not standard Mozilla ParallelArray thing which could help making parallel execution. I don't know if there's something similar on V8.
As long as the dimensions of the array are very low ( in order of 10's) then there is not much a difference in the performance, but when the size of the array increases to a very large value, then using conventional for loop is a great and better method, because we just need to loop through the elements and get a value at a specific index as we point, but in other methods, not only we are getting the value at an index, but also additional information such as the index, (in map, reduce, forEach) and accumulator value (in reduce). And these methods as need an a callback function, they both take up a great deal of stock on the memory for callbacks which further reduces the performance speed.
You can check the justification of this with the following script.
Just see the values that are console logged.
var scripts=[];
// GLOBAL variales declaration
var a=[];
function preload() {
for(var i=0;i<100000;i++) a[i]=i;
}
preload();
// TEST function 0
scripts.push(function() {
var sum=0;
a.forEach(function(v) {
sum+=v;
});
//console.log(sum);
});
// TEST function 1
scripts.push(function() {
a.reduce(function(acc,v) {
return acc+v;
});
});
// TEST function 2
scripts.push(function() {
var sum=0;
for(var i=0;i<a.length;i++) {
sum+=a[i];
}
});
// EVALUATION
scripts.forEach(function(f,index) {
var date=new Date();
for(var i=0;i<10000;i++) {
f();
}
console.log("call "+index+" "+(new Date()-date));
});
It is easily overlooked, but the key to getting the benefits of MapReduce is to
A) Exploit the optimized shuffle. Often, your map and reduce functions can be implemented in a slow language, as long as the shuffle - the most expensive operation - is well optimized, it will still be fast and scalable.
B) Exploit the checkpointing functionality to recover from node failures (but hopefully, your CPU cores won't fail).
So in the end, map-reduce is actually neither about the map, nor the reduce functions. It's about the framework around it; which will give you good performance even with bad "map" and "reduce" functions (unless you lose control over your data set size in the shuffle step!).
The gains to be obtained from doing a multi-threaded map-reduce on a single node are fairly low, and most likely there are much better ways of parallelizing your shop for shared memory architectures than map-reduce...
Unfortunately, there is a lot of hype (and too little understanding) surrounding mapreduce these days. If you look up the original paper, it goes into detail about "Backup Tasks", "Machine Failures" and "locality optimization" (neither of which makes sense for an in-memory single-host use case).
Just because it has a "map" and a "reduce" doesn't make it a "mapreduce" yet.
It's only a MapReduce if it has an optimized shuffle, node crash and straggler recovery.

Categories