Optimizing stack memory read/writes in JavaScript? - javascript

Let's say we have the following function with a loop that writes some memory variable within each iteration of the loop.
function myFunction() {
for (var i = 0; i < 10000; i++) {
let myStackVariable = i;
// do something with myStackVariable
}
}
But let's say we re-write this loop to declare the variable only once outside of the loop and then re-assign it during the loop.
function myFunction() {
let myStackVariable;
for (var i = 0; i < 10000; i++) {
myStackVariable = i;
// do something with myStackVariable
}
}
I'm pretty sure that in any decent C compiler will optimize only a single variable in the stack and consistently use that memory location.
Will JavaScript likely do the same? Is there any benefit performance wise to doing the latter? Is it worth writing one way rather than the other. I know, I know - premature optimization is the root of all evil - but I am more curious than anything.
I tried running tests with n = 100000000 and the results were the same, but I'm unsure if my example was just too simple since there are no recursions, etc.

Related

Why for-in loops can't have multiple variable declarations?

let example = {
a:20,
b:40,
c:60
}
for(let j=0,i in example){
console.log(example[i]*j);
j++;
}
Why normal for loop can have multiple variable declarations, but for-in loop cannot? Or am I doing this somehow wrong?
You're writing a code that's not syntactically correct.
in JavaScript you cannot use for-in expression with any other assignment expression.
You can simply pull out the j=0 assignment out of the for loop and that should fix the error
let example = {
a:20,
b:40,
c:60
}
let j=0
for(i in example){
console.log(example[i]*j);
j++;
}
[Edit] I have the found the following content in the official MDN site for the same scenario
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in
As per the site - it's a publicly known issue that ChromeV8 and other browsers are trying to look into
For more info check the following references
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Invalid_for-in_initializer
https://bugzilla.mozilla.org/show_bug.cgi?id=748550
https://bugzilla.mozilla.org/show_bug.cgi?id=1164741
I can understand the frustration, you're using the same keyword so why doesn't it behave similar? But I think you should think about it this way:
for is a way to define a loop, for as long as some condition is true, with different way for how to define that condition.
In a regular for loop, you loop as long as the middle part (the condition) is true:
for(let i = 0; i < 10; i++)
This is similar to how a while loop might work, but it's a syntactic short cut:
let i = 0;
while (i < 10) {
i++;
}
So the for..in is a for loop that has another sort of condition, for every property in this object, so as long as you have more properties it will keep looping.
You could write that like this as well:
const keys = Object.keys(example);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const value = example[key];
}
You also have for...of, which loops over items in a array, but that is syntactic sugar for:
for(let i = 0; i < array.length; i++) { const item = array[i]; }
Also consider how a do...while loop is like a while loop but with some slightly different rules and behavior. Rather than getting frustrated with the syntax try to understand how it's saving you time by making your code a little less wordy, but in order to do that it needs to be a little different for each case. The alternative would be to have very many language keywords.
I tried changing your code to not declare any variables inside the parentheses of the for loop. I have never seen this done; maybe it's possible, but it would be simpler to declare a variable above the for loop, like this (assuming that's what you were hoping to do):
let example = {
a:20,
b:40,
c:60
}
let j=0
for(let i in example){
console.log(example[i]*j);
j++;
}
Edit: As mentioned in the comments: "You should probably add a let before the i declaration, otherwise it's going to be globally defined." I've just changed that in the snippet!

JavaScript loop best practice

I'm doing a tutorial on JavaScript. The following is from a section on performance:
Each statement in a loop, including the for statement, is executed for each iteration of the loop.
Statements or assignments that can be placed outside the loop will
make the loop run faster.
This is given as an example of bad code:
var i;
for (i = 0; i < arr.length; i++) {
And this is given as an example of good code:
var i;
var l = arr.length;
for (i = 0; i < l; i++) {
This is not something I can remember seeing as a best practice in languages that are more focused on performance than JavaScript. In fact, the bad code example seems to be preferred.
Is this best practice something particular for JavaScript, or is is true for other languages?
Bad Practice
for (i = 0; i < arr.length; i++) {
For every iteration in the loop, the condition is evaluated. If it is being arr.length then every time you are trying to access length property from arr. However, on the other hand, if you are storing it in a variable you are avoiding that operation.
Of all the ways to loop in javascript, the for-in loop is the safest in my opinion.
It can loop through the properties in an object.
let user = {first:"billy", last:"bob"};
for(let i in user){
console.log(i);
console.log(user[i]);
}
It doesn't throw an error if the variable is null
let empty = null;
for (let i in empty){
}
It works with arrays
let arr = [3,2,1];
for (let i in arr){
console.log(i);
console.log(arr[i]);
}
.map
.filter
.reduce
.forEach
throw errors with anything but arrays(null, objects etc)
So if you want one loop that works for everything, for-in is you what you want.

Best practice: Javascript for loop

What is the best practice for writing a JavaScript for loop?
I started out writing it like this:
for(var i = 0; i < array.length; i++){
//do stuff
}
But then I found that calculating the length on each pass is not ideal, so it should be more like:
var len = array.length;
for(var i = 0; i < len; i++){
//do stuff
}
But then the loop is faster if you decrease rather than increase:
var lenArr = array.length - 1;
for(var len = lenArr; len > 0; len--){
//do stuff
}
This kind of loop however doesn't really work if you want to break just one loop in a cluster of nested loops, so you should therefore get into the habit of using labels:
var lenArr = array.length - 1;
var lenArr2 = array2.length - 1;
loop1: for(var len = lenArr; len > 0; len--){
loop2: for(var len2 = lenArr2; len2 > 0; len2--){
//do stuff
break loop2;
}
}
Is there something else that will need to change, or is this the best practice for writing for loops in JavaScript?
IF you have array than make use of forEach
array.forEach(ele=> {
});
that way you can keep code clean and easy to understand and dont have to do length related code.
Break is not going to work with forEach but you can write return for coming out of forEach like
array.forEach(ele=> {
ele.array.forEach(ele=> {
//do stuff
return;
});
});
Note:
for loop is faster.
forEach is slower, but better fits functional programming paradigms.
Answer is based on title of question : Best Practice that why given suggestion to make use of forEach over for.
Actually, i prefer for...of as you can still break and its much less typing and its definetly more readable:
for(const el of array)
If you need indices too:
for(const [index, el] of array.entries())
Or if you need to iterate from back to front:
for(const el of array.reverse())
Concerning saving array.length: Even though in the early days of JavaScript it made a difference to save the .length value in a variable, modern JavaScript engines will run the for loop just as fast if you write it as in the first version.
Iterating backward is also not guaranteed to run faster on modern engines. There is also the consideration that CPUs are optimised to anticipate forward memory references, although this will only be relevant when the JS engine has decided to store the array as a contiguous block of memory.
As for the use of labels: most would not consider this best practice. Where the previous optimisation (concerning .length) concerns all iterations of the loop, this issue only applies to a single exit out of both loops. Whatever solution you use, it represents constant time, and could not be a determining factor in the overall performance of the loop.
So certainly in this case, I would go with good coding habits over tiny optimisation considerations. When you want to exit just the current loop, a single break is enough.
If you want to exit quickly from nested loops, then consider placing them in a function, so you can use return:
function performNestedLoop(array, array2) {
for(let i = 0; i < array.length; i++){
for(var j = 0; j < array2.length; j++){
//dostuff
if (exitCondition) return;
}
}
}
As to best practice: this really depends on what you need to achieve. There are several array methods that provide iteration, like forEach, map, reduce, reduceRight, filter, some, every, find, findIndex, includes,... each with their purpose. If they fit the purpose, then go with them. If you don't need the index, but just the value, then use for..of. If you really need every speck of optimatisation, then the old fashioned for loop is a likely winner.
You can use Array.forEach
Advantage of using forEach are as follows
Provides functional scoping, and whenever you need to perform some async function in the loop, you will not be required to created any IIFE
It keeps your code tidy and more contextual
Sample Code
arr.forEach(function(item, index){
// do stuff
});

Javascript, counters and real-time applications

I'm currently working on a game and i have decided to go with javascript to make a prototype. During the development i noticed that i use a lot of counters in this way:
function update() {
for(var i = 0; i < n; i++) {
// do stuff
}
for(var i = 0; i < m; i++) {
// do other stuff
}
}
Keeping in mind that this is a real time application so the update function is executed almost 60 times per second, we can say that i'm creating a lot of variables. I was wondering how that piece of code would affect performance (does the javascript engine make some optimization here?) and how the garbage collector behaves in this situation (i don't even know how the GC manages primitive types...).
For now i changed the code to look like this:
var counters = {};
function update() {
for(counters['taskA'] = 0; counters['taskA'] < n; counters['taskA']++) {
// do stuff
}
for(counters['taskB'] = 0; counters['taskB'] < m; counters['taskB']++) {
// do other stuff
}
}
Does this code make any difference?
There shouldn't be any significant performance difference. However, the counters variable will not be garbage collected if its on the global scope. It will only get GCed when it goes out of scope so if its within another function that will be mostly fine.
On your first example the i variables definitely get GCed as there within the update function.

Is it bad practice to use the same variable name in multiple for-loops?

I was just linting some JavaScript code using JSHint. In the code I have two for-loops both used like this:
for (var i = 0; i < somevalue; i++) { ... }
So both for-loops use the var i for iteration.
Now JSHint shows me an error for the second for-loop: "'i' is already defined". I can't say that this isn't true (because it obviously is) but I always thought this wouldn't matter as the var i is only used in that specific place.
Is it bad practice to use for-loops this way? Should I use a different variable for each for-loop in my code like
//for-loop 1
for (var i = 0; ...; i++) { ... }
//for-loop 2
for (var j = 0; ...; j++) { ... }
Or is this on e of the errors I can ignore (because it doesn't break my code, it still does what it is supposed to do)?
JSLint btw. stops validating at the first for loop because I don't define var i at the top of the function (that's why I switched to JSHint in the first place). So according to the example in this question: Should I use JSLint or JSHint JavaScript validation? – I should use for-loops like this anyway to confirm JSLint:
...
var i;
...
//for-loop 1
for (i = 0; ...; i++) { ... }
...
//for-loop 2
for (i = 0; ...; i++) { ... }
This also looks good to me, because this way I should avoid both errors in JSLint and JSHint. But what I am uncertain about is if I should use a different variable for each for-loop like this:
...
var i, j;
...
//for-loop 1
for (i = 0; ...; i++) { ... }
//for-loop 2
for (j = 0; ...; j++) { ... }
So is there a best practice for this or could I just go with any of the code above, meaning I choose "my" best practice?
Since variable declarations are hoisted to the top of the scope in which they appear the interpreter will effectively interpret both versions in the same way. For that reason, JSHint and JSLint suggest moving the declarations out of the loop initialiser.
The following code...
for (var i = 0; i < 10; i++) {}
for (var i = 5; i < 15; i++) {}
... is effectively interpreted as this:
var i;
for (i = 0; i < 10; i++) {}
for (i = 5; i < 15; i++) {}
Notice that there is really only one declaration of i, and multiple assignments to it - you can't really "redeclare" a variable in the same scope.
To actually answer your question...
is there a best practice for this or could I just go with any of the code above?
There are varying opinions on how best to handle this. Personally, I agree with JSLint and think the code is clearer when you declare all variables together at the top of each scope. Since that's how the code will be interpreted, why not write code that looks as it behaves?
But, as you've observed, the code will work regardless of the approach taken so it's a style/convention choice, and you can use whichever form you feel most comfortable with.
It has been mentioned only in the comment by #TSCrowder: If your environment supports it (Firefox, Node.js), in ES6 you can use let declaration
//for-loop 1
for (let i = 0; ...; i++) { ... }
//for-loop 2
for (let i = 0; ...; i++) { ... }
which limits the scope to within the for-loop. Bonus: JSHint stops complaining.
Variables in javascript are function scoped (not block scoped).
When you define var i in a loop, it remains there in loop and also in the function having that loop.
See below,
function myfun() {
//for-loop 1
for (var i = 0; ...; i++) { ... }
// i is already defined, its scope is visible outside of the loop1.
// so you should do something like this in second loop.
for (i = 0; ...; j++) { ... }
// But doing such will be inappropriate, as you will need to remember
// if `i` has been defined already or not. If not, the `i` would be global variable.
}
The reason JSHint shows the error is because in JS variable scope is function and variable declarations are hoisted to the top of the function.
In Firefox you can use let keyword to define block scope, but is not currently supported by other browsers.
The let keyword is included ECMAScript 6 specification.
I know this question has been answered, but if you want super for loops, write them like this:
var names = ['alex','john','paul','nemo'],
name = '',
idx = 0,
len = names.length;
for(;idx<len;++idx)
{
name = names[idx];
// do processing...
}
A couple of things going on here...
The array length is being stored in len. This stops JS evaluating names.length every iteration
The idx increment is a PRE-INCREMENT (e.g. ++idx NOT idx++). Pre-increments are natively faster than Post-increments.
The storing of a reference to name. This is optional but recommended if you'll be using the name variable a lot. Every call to names[idx] requires finding the index in the array. Whether this search be a linear search, tree search or hash table, the find is still happening. So store a reference in another variable to reduce lookups.
Finally, this is just my personal preference, and I have no proof or any performance benefits. However I always like initialising variables to the type they're going to be e.g. name = '',.
The best practice is to reduce the scope of variables, so the best way to declare iteration variable for the loops is
//for-loop 1
for (var i = 0; ...; i++) { ... }
//for-loop 2
for (var j = 0; ...; j++) { ... }
I know the scope of the variables declared with var but I am taking about code readability here.

Categories