JavaScript's Statement Performance Questions - javascript

Can you guys help me determine the performance difference of each of these
statements? Which one would you use?
Making a new Array using
- var new_list = new Array(); //or
- var new_list = [];
Appending element using
- push('a')
- new_list[i]; (if i know the length)
Ternary operator or if() {} else (){}
Trying to make isodd function, which is faster
(! (is_even)) or (x%2!=0)
forEach() or normal iteration
one more
a= b = 3; or b=3; a=b;
[edit: I'm making a Math Library. So any performance hacks discussions are also welcome :) ]
Thanks for your help.

I've always assumed that since (x&1) is a bitwise operation, it would be the fastest way to check for even/odd numbers, rather than checking for the remainder of the number.

Performance characteristics for all browser (especially at the level of individual library functions) can vary dramatically, so it's difficult to give meaningful really meaningful answers to these questions.
Anyhoo, just looking at the fast js engines (so Nitro, TraceMonkey, and V8)
[ ] will be faster than new Array -- new Array turns into the following logic
cons = lookup property "Array", if it can't be found, throw an exception
Check to see if cons can be used as a constructor, if not: throw an exception
thisVal = runtime creates a new object directly
res = result of calling cons passing thisVal as the value for this -- which requires logic to distinguish JS functions from standard runtime functions (assuming standard runtime functions aren't implemented in JS, which is the normal case). In this case Array is a native constructor which will create and return a new runtime array object.
if res is undefined or null then the final result is thisVal otherwise the final result is res. In the case of calling Array a new array object will be returned and thisVal will be thrown away
[ ] just tells the JS engine to directly create a new runtime array object immediately with no additional logic. This means new Array has a large amount of additional (not very cheap) logic, and performs and extra unnecessary object allocation.
newlist[newlist.length] = ... is faster (esp. if newlist is not a sparse array), but push is sufficiently common for me to expect engine developers to put quite a bit of effort into improving performance so this could change in time.
If you have a tight enough loop there may be a very slight win to the ternary operator, but arguably that's an engine flaw in the trival case of a = b ? c : d vs if (b) a = c; else a = d
Just the function call overhead alone will dwarf the cost of more or less any JS operator, at least in the sane cases (eg. you're performing arithmetic on numbers rather than objects)
The foreach syntax isn't yet standardised but its final performane will depend on a large number of details; Often JS semantics result in efficient looking statements being less efficient -- eg. for (var i in array) ... is vastly slower than for (var i = 0; i < array.length; i++) ... as the JS semantics require in enumeration to build up a list of all properties on the object (including the prototype chain), and then checking to make sure that each property is still on the object before sending it through the loop. Oh, and the properties need to be converted from integers (in the array case anyway) into strings, which costs time and memory.

I'd suggest you code a simple script like:
for(var i = 0; i < 1000; i++){
// Test your code here.
}
You can benchmark whatever you want that way, possibly adding timing functions before and after the for statement to be more accurate.
Of course you'll need to tweak the upper limit (1000 in this example) depending on the nature of your operations - some will require more iterations, others less.

Both are native constructors probably no difference.
push is faster, it maps directly to native, where as [] is evaluative
Probably not much of a difference, but technically, they don't do the same thing, so it's not apples to apples
x%2, skips the function call which is relatively slow
I've heard, though can't find the link at the moment, that iteration is faster than the foreach, which was surprising to me.
Edit: On #5, I believe the reason is related to this, in that foreach is ordered forward, which requires the incrementor to count forward, whereas for loops are ever so infinitesimally faster when they are run backward:
for(var i=a.length;i>-1;i--) {
// do whatever
}
the above is slightly faster than:
for(var i=0;i<a.length;i++) {
// do whatever
}

As other posters suggest, I think doing some rough benchmarking is your best bet... however, I'd also note that you'll probably get very different results from different browsers, since I'm sure most of the questions you're asking come down to specific internal implementation of the language constructs rather than the language itself.

This page says push is slower.
http://dev.opera.com/articles/view/efficient-javascript/?page=2

Related

Why does Javascript `iterator.next()` return an object?

Help! I'm learning to love Javascript after programming in C# for quite a while but I'm stuck learning to love the iterable protocol!
Why did Javascript adopt a protocol that requires creating a new object for each iteration? Why have next() return a new object with properties done and value instead of adopting a protocol like C# IEnumerable and IEnumerator which allocates no object at the expense of requiring two calls (one to moveNext to see if the iteration is done, and a second to current to get the value)?
Are there under-the-hood optimizations that skip the allocation of the object return by next()? Hard to imagine given the iterable doesn't know how the object could be used once returned...
Generators don't seem to reuse the next object as illustrated below:
function* generator() {
yield 0;
yield 1;
}
var iterator = generator();
var result0 = iterator.next();
var result1 = iterator.next();
console.log(result0.value) // 0
console.log(result1.value) // 1
Hm, here's a clue (thanks to Bergi!):
We will answer one important question later (in Sect. 3.2): Why can iterators (optionally) return a value after the last element? That capability is the reason for elements being wrapped. Otherwise, iterators could simply return a publicly defined sentinel (stop value) after the last element.
And in Sect. 3.2 they discuss using Using generators as lightweight threads. Seems to say the reason for return an object from next is so that a value can be returned even when done is true! Whoa. Furthermore, generators can return values in addition to yield and yield*-ing values and a value generated by return ends up as in value when done is true!
And all this allows for pseudo-threading. And that feature, pseudo-threading, is worth allocating a new object for each time around the loop... Javascript. Always so unexpected!
Although, now that I think about it, allowing yield* to "return" a value to enable a pseudo-threading still doesn't justify returning an object. The IEnumerator protocol could be extended to return an object after moveNext() returns false -- just add a property hasCurrent to test after the iteration is complete that when true indicates current has a valid value...
And the compiler optimizations are non-trivial. This will result in quite wild variance in the performance of an iterator... doesn't that cause problems for library implementors?
All these points are raised in this thread discovered by the friendly SO community. Yet, those arguments didn't seem to hold the day.
However, regardless of returning an object or not, no one is going to be checking for a value after iteration is "complete", right? E.g. most everyone would think the following would log all values returned by an iterator:
function logIteratorValues(iterator) {
var next;
while(next = iterator.next(), !next.done)
console.log(next.value)
}
Except it doesn't because even though done is false the iterator might still have returned another value. Consider:
function* generator() {
yield 0;
return 1;
}
var iterator = generator();
var result0 = iterator.next();
var result1 = iterator.next();
console.log(`${result0.value}, ${result0.done}`) // 0, false
console.log(`${result1.value}, ${result1.done}`) // 1, true
Is an iterator that returns a value after its "done" is really an iterator? What is the sound of one hand clapping? It just seems quite odd...
And here is in depth post on generators I enjoyed. Much time is spent controlling the flow of an application as opposed to iterating members of a collection.
Another possible explanation is that IEnumerable/IEnumerator requires two interfaces and three methods and the JS community preferred the simplicity of a single method. That way they wouldn't have to introduce the notion of groups of symbolic methods aka interfaces...
Are there under-the-hood optimizations that skip the allocation of the object return by next()?
Yes. Those iterator result objects are small and usually short-lived. Particularly in for … of loops, the compiler can do a trivial escape analysis to see that the object doesn't face the user code at all (but only the internal loop evaluation code). They can be dealt with very efficiently by the garbage collector, or even be allocated directly on the stack.
Here are some sources:
JS inherits it functionally-minded iteration protocol from Python, but with results objects instead of the previously favoured StopIteration exceptions
Performance concerns in the spec discussion (cont'd) were shrugged off. If you implement a custom iterator and it is too slow, try using a generator function
(At least for builtin iterators) these optimisations are already implemented:
The key to great performance for iteration is to make sure that the repeated calls to iterator.next() in the loop are optimized well, and ideally completely avoid the allocation of the iterResult using advanced compiler techniques like store-load propagation, escape analysis and scalar replacement of aggregates. To really shine performance-wise, the optimizing compiler should also completely eliminate the allocation of the iterator itself - the iterable[Symbol.iterator]() call - and operate on the backing-store of the iterable directly.
Bergi answered already, and I've upvoted, I just want to add this:
Why should you even be concerned about new object being returned? It looks like:
{done: boolean, value: any}
You know, you are going to use the value anyway, so it's really not an extra memory overhead. What's left? done: boolean and the object itself take up to 8 bytes each, which is the smallest addressable memory possible and must be processed by the cpu and allocated in memory in a few pico- or nanoseconds (I think it's pico- given the likely-existing v8 optimizations). Now if you still care about wasting that amount of time and memory, than you really should consider switching to something like Rust+WebAssembly from JS.

Indexing through a constant string

I was playing with a constant string in a loop from another question…
Here it is:
str = "abcd";
for (i = 0; i < 4; i++) {
console.log(str[i]);
}
… and I ended up doing that:
for (i = 0; i < 4; i++) {
console.log("abcd"[i]);
}
I didn't know this kind of coding was working before I tried!
How is this way of doing called?
Should it be avoided for any technical reason?
Thanks for any answer.
How is this way of doing called?
I'm not aware of it having any specific name. You're just using a string literal inside the loop.
Should it be avoided for any technical reason?
With a string literal it probably doesn't matter, because string literals define primitive strings (and are likely reused by the JavaScript engine, as they're immutable). But if you were creating an object every time, that would be unnecessary overhead compared with just creating it once and reusing it.
For instance, if you were doing this:
for (var i = 0; i < 4; i++) {
console.log([1, 2, 3, 4][i]);
}
That code tells the JavaScript engine to create that array each time the loop body runs, which is fast, but not instantaneous. (The JavaScript engine might be able to analyze the code and optimize it if the code were used enough that it seemed worth bothering, but that's a different topic.)
The way to tried is okay but not very useful as if you specify the string in the loop it becomes static to the loop.
It is advised to use Variable insteads of "HARDCODED" values.
All your code really does is do away with the variable and index the "array-like" object directly.
Strings are "array-like" objects. They have .length property and can be indexed just as Arrays can be. They are not however, actual arrays and don't support the full Array API. JavaScript is full of "array-like" objects and they are certainly not anything to be avoided. To the contrary, it is a great feature of the language to be able to leverage this. It's just important to know when you have an actual Array and when you have an "array-like" object, so you don't use the latter incorrectly.
So, because "abcd" is array-like, there is no reason you can't place an index right after it:
"abcd"[2]
Scott Marcus explains what's happening here well. As far as whether this should be avoided, many believe it is better to access chars in a string using chatAt() instead of bracket notation. Namely because:
Bracket notation is part of ECMAScript 5 and therefore not universally supported
The similarity to bracket notation of an array or hash object can be confusing. For instance, strings are immutable so you cannot set the value of a string at a certain index as you can with an array or hash. Using chatAt() can therefore elucidate that one should not expect this to be possible.
Source:
string.charAt(x) or string[x]?

Assignment expression in while condition is a bad practice?

This article explains why I have a warning if I use a code like this:
var htmlCollection = document.getElementsByClassName("class-name"),
i = htmlCollection.length,
htmlElement;
// Because htmlCollection is Live, we use a reverse iteration.
while (htmlElement = htmlCollection[--i]) { // **Warning?! Why?!**
htmlElement.classList.remove("class-name");
}
But this no explaination about « why is a bad practice to assignment expression in a while condition? ».
I also read this stackoverflow answers that point this practice as good. So...
There is a performance problem with while (element = element.parentNode) syntax-like or is just a style-code recommandation?
By the way, seems the « --i » operator is also a bad practice. I read in this article :
The ++ (increment) and -- (decrement) operators have been known to contribute to bad code by encouraging excessive trickiness.
It's some sort of joke?
There should be no performance problems with it (arguably, indexing with prefix increment can be slightly slower than postfix increment, due to issues with CPU pipelines; this is a microoptimization so ridiculously micro that it almost certainly means nothing in the context of JS engine overhead, even in C the compiler is likely to reorder expressions if it can to ensure it's not stalled waiting on the increment).
Either way, the main argument against assignment in a conditional is basically that most of the time when you do it, it's a mistake (you meant == or in JS, ===). Some code checkers (and C# requires this as a language feature to avoid accidents) are satisfied if you wrap the assignment in an additional layer of parens, to say, "Yup, I really meant to assign" (which is also necessary when you're comparing the result of the assignment to some other value; omitting the parens would instead compare, then assign a boolean, which even more likely to be wrong).
Some people have a hate on for increment/decrement operators used as part of larger expressions, because remembering order of operations is hard I guess, and because C programmers have been known to write horrible things like ++*++var and the like. I ignore these people; just don't use it for excessively tricky things.
As an orthogonal approach, and possible 'cleaner/clearer' there is:
// var htmlCollection = document.getElementsByClassName("class-name");
var htmlCollection = document.querySelectorAll('.class-name');
for(let htmlElement of htmlCollection) {
htmlElement.classList.remove("class-name");
}
as a method of iterating over DOM elements.
UPDATED to include suggestion from ShadowRanger below.

When/why to use map/reduce over for loops

So I am getting into a bit of object manipulation in JavaScript for the first time and I have a question I'm wondering if anyone could answer.
When I have an object I want to manipulate I could do something to the extent of a few nested for loops, however there are functions built into JavaScript, like map/reduce/filter, and libraries like lodash/underscore.
I assume the latter (map/reduce/filter and the libraries) are better practice but I'm just curious as to why.
I am doing some pretty basic object manipulation that could be solved with a few well placed for loops to grab and change the right keys/values in the object, but can be easily done with the functions/libraries in JS. Just curious as to how they are better - like better performance/cleaner code/ease of use/whatever else.
Apologies, there is no code. I would very much appreciate anyone helping me understand more here.
Edit - so taking from the examples for map()
I could take the example for javascript.map
var kvArray = [{key:1, value:10}, {key:2, value:20}, {key:3, value: 30}];
var reformattedArray = kvArray.map(function(obj){
var rObj = {};
rObj[obj.key] = obj.value;
return rObj;
});
I could do something like
var kvArray = [{key:1, value:10}, {key:2, value:20}, {key:3, value: 30}];
var reformattedArray = [];
for(var object in kvArray){
//combine both values into object inside of kvArray[object]);
};
A lot less code - but any other benefits worth knowing about?
I know I'm replying to an old answer but just wanted to point out for future readers.
Map reduce and filter functions come from the functional programming world.
These are first class built-in operators in languages like Lisp, Haskell, and others(ml?).
Functional languages tend to prefer to run operators over immutable data than make the code run over the data to operate on it (say loops).
So they provide simpler but powerful interfaces like map, filter and reduce when compared to providing for and while loops.
It also helps them satisfy other requirements like immutability etc. That's why maps give u back a new map instead of mutating the old one. These are very good from a concurrency point of view, though they may be slower in certain contexts.
This approach usually leads to fewer errors in code in multi-threaded or high concurrency apps.
When multiple actors act on the same piece of data, immutability helps keep code from stepping on each other's toes.
Since javascript tries to be partially functional by providing some functionalities of functional programming languages, it might have made sense to implement map, filter and reduce functions in it too.
YMMV depending on what you are doing with the tools you are given.
If your code works better with a for loop, go for it.
But if you ever find asynchronous code munching on common data and you end up splitting your hairs trying to debug a loop.
Say hi, to map, reduce and filter.
.map() allows you to create a new array by iterating over the original array and allowing you to run some sort of custom conversion function. The output from .map() is a new array.
var orig = [1,2,3,4,5];
var squares = orig.map(function(val) {
return val * val;
});
console.log(squares); // [1,4,9,16,25]
.reduce() allows you to iterate over an array accumulating a single result or object.
var orig = [1,2,3,4,5];
var sum = orig.reduce(function(cum, val) {
return cum + val;
}, 0);
console.log(sum); // 15
These are specialized iterators. You can use them when this type of output is exactly what you want. They are less flexible than a for loop (for example, you can't stop the iteration in the middle like you can with a for loop), but they are less typing for specific types of operations and for people that know them, they are likely a little easier to see the code's intent.
I have not myself tested the performance of .map() and .reduce() versus a for loop, but have seen tests for .forEach() which showed that .forEach() was actually slower in some browsers. This is perhaps because each iteration of the loop with .forEach() has to call your callback function, whereas in a plain for loop, you do not have to make such a function call (the code can be directly embedded there). In any case, it is rare that this type of performance difference is actually meaningful and you should generally use whichever construct makes clearer, easier to maintain code.
If you really wanted to optimize performance, you would have to write your own test case in a tool like jsperf and then run it in multiple browsers to see which way of doing things was best for your particular situation.
Another advantage of a plain for loop is that it can be used with array-like objects that support indexing, but do not support .reduce() and .map().
And, a for/of loop can be used with any object that implements the iterator protocol such as HTMLCollection.
This is like asking if I like basketball or football better. Both have their positives.
If you have 10 developers look at your for loop, 9 out of 10 will know what you are doing right away. Maybe half will have to look up what the map() method is, but then they'll also know what's going on. So in this respect, a for loop is easier for others to read.
On the flip side, map() will save you two or three lines of code.
As far as performance goes, you'll find map() is built internally with something akin to a for loop. You might see a few milliseconds of difference when it comes to performance speeds if you run them through large iterations; but they'll never be recognizable to an end user.
forEach(): Executes a provided function(callback) once for each array element. Doesn’t return anything (undefined) but this callback is allowed to mutate the calling array.
map(): Executes a provided function(callback) once for each array element and creates a new array with the results of this execution. It cannot mutate the calling array content.
Conclusion
Use map() when you need to return a new array.
Use forEach() when you want to change the original array
Use for when you need more control over the iteration (eg: you want to iterate every three elements (i + 3))
Bumped into this while searching for something else. So trying to answer it even if it is a old thread as the concepts applies no matter what.
If you consider performance and flexibility, "for" loop always beats the others, just because it doesn't have the overhead of calling a function for each iteration and can be used for any purpose.
But, there are other gains with functions like forEach, map, reduce etc (let's call them functional methods). It is mainly the readability, maintainability.
Below are few drawbacks of for loop
Introduces new variables to the scope, just for the counter/iteration
Hard to debug errors, due to un-intentional changes to counter variables. This becomes more difficult and the chances to make a mistake increases more as the number of loops with in loops increase
Developers have the habit of using loop variables as i, j, k. It is very easy to lose the track of which counter and which inner loop the code is executing once the loop increases certain lines of code
With ES6, we have at least limited/local scope introduced by 'let'. But before, the variables introduced by for loop have a function scope causing even more accidental errors
To avoid all of these, it is suggested to use functions like forEach, map, reduce when you know what you have to do (Not to forget most of these functional methods offer immutability). A small sacrifice in terms of performance for the greater good and more succinct code.
With ES6, most of the functional methods are supported by the language itself. They are optimised and we don't have to rely on libraries like lodash (unless there is a severe performance gain).
Just bumped into this and found that none of the answers highlights one important difference between for-loop and map as to when to use one over the other:
With map you can't break out of an iteration which you can with for-loop.
For e.g, you can't do this
const arr = [5, 6, 9, 4];
arr.map(elem=>{
if(elem === 5){
break; //This is not allowed
}
})
Summarising the differences between higher-order array methods (map, reduce, filter, etc. - I'll refer to these as HOMs) vs for loops, and including a few other points:
Counter variables: for loops introduce variables that introduce errors such as: OBOE; block scoping errors (which are complicated further by the differences in let and var declaration scoping)
Availability: HOMs are only available to objects that are arrays (Array.isArray(obj)); for loops can be used on objects that implement the iterator protocol (which includes arrays),
Early execution exit: there is none for HOMs; loops have the break and return statement for this,
Consecutive async iteration execution: Not possible in HOMs. Notice that only a loop can delay between console logging executions:
// Delays for a number of milliseconds
const delay = (ms = 1000) => new Promise(resolve => setTimeout(resolve, ms));
const items = ['a', 'b', 'c'];
const printItem = async (item) => {
await delay();
console.log(item);
}
const testForLoopParallelism = async () => {
for (const item of items) {
await printItem(item);
}
};
const testHigherOrderParallelism = () => {
return Promise.all(items.map(async item => await printItem(item)));
}
const run = async () => {
// Prints consecutively at a rate of ~1s, for a total of ~3s
console.time('for');
await testForLoopParallelism();
console.timeEnd('for');
// Prints all concurrently, for a total of ~1s
console.time('HOM');
await testHigherOrderParallelism();
console.timeEnd('HOM');
};
run();
Less importantly but worth noting:
Verbosity: array HOMs may be shorter than for loops
Subjectively easier to read: this can be argued for both HOMs and for for ... in loops
Subjectively better understood: loops may be more well known than HOMs for Javascript newcomers
Performance: May have performance differences that may need to be considered in high performance codebases on a case-by-case basis
Immutability aid: May aid in providing immutability - although it is possible to create mutations using either HOMs or for loops, e.g.,
items.map((item) => {
items.push(item);
return `${item}x`;
});
map, reduce, etc are functions that container-like data-structures should implement so that consumers can make use of them without having to understand their internals. These functions accept your logic as input. This allows you to implement changes to the internals of those data-structures without affecting their consumers.
The real reason why map is superior to for loops is because they are much easier to develop with as your application evolves. What if your requirements change such that you now have an object?
import map from 'lodash/fp/map';
import mapValues from 'lodash/fp/mapValues';
const before = map(logic, data);
const after = mapValues(logic, data);
And again, what if your requirements change such that now you have a tree? Well, now you're a good developer that realises that the code that is responsible for traversing the tree should be separated from the business logic. It should be written once, thoroughly tested once, be maintained by the team that owns the data-structure, and accept business logic as input. All so that consumers do not have to worry about its internals.
Instead, consumers should just do this.
import { mapTreeValues } from 'tree'
const before = map(logic, data);
const after = mapTreeValues(logic, data);
Long story short, for should only ever be used by owners of data structures to implement functions such as map, reduce, etc. These functions should never be coupled to business logic, instead they should accept it as input. Remember the single responsibility principle?
Aside: To preempt comparison with custom iterables, there are benefits to these being higher-order functions to improve ease of composition. For example:
getUser().then(updateUser)
getUsers().then(map(updateUser))

workaround: javascript dictionary which takes objects as keys

I read a few questions and answers about javascript dictionary implementations, but they don't meet my requirements:
the dictionary must be able to take objects as keys
the values must be accessible by the []-operator
So I came up with the idea to overwrite the valueOf-method in Object.prototype, as follows:
Object.__id__ = 0;
Object.prototype.valueOf = function() {
if(!this.__id__)
this.__id__ = ++Object.__id__;
return "__id__" + this.__id__;
}
Object.prototype.toString = Object.prototype.valueOf;
//test
var x = {p1: "5"};
var y = [6];
var z = {};
z[x] = "7";
z[y] = "8";
console.log(z[x], z[y]);
I tested this with google-chrome and it seems to work well, but I'm a bit sceptical, whether this will cause some drawbacks, since it was so easy to implement.
Considering that the valueOf method is not used for other purposes in the whole code, do you think there are any disadvantages?
It's an interesting idea. I suggest my jshashtable. It meets your first requirement but not the second. I don't really see the advantage of insisting on using the square bracket property access notation: do you have a particular requirement for it?
With jshashtable, you can provide a hashing function to the Hashtable constructor. This function is passed an object to be used as a key and must return a string; you could use a function not dissimilar to what you have there, without having to touch Object.prototype.
There are some disadvantages to your idea:
Your valueOf method will show up in a for...in loop over any native object;
You have no way determining which keys should be considered equal, which is something you may want to do. Instead, all keys will be considered unique.
This won't work with host objects (i.e. objects provided by the environment, such as DOM elements)
It is an interesting question, because I had so far assumed that any object can be used as an index (but never tried with associative arrays). I don't know enough about the inner workings of JavaScript to be sure, but I'd bet that valueOf is used somewhere else by JavaScript, even if not in your code. You might run into seemingly inexplicable problems later. At least, I'd restrict myself to a new class and leave Object alone ;) Or, you explicitly call your hashing function, calling it myHash() or whatever and calling z[x.myHash()] which adds clutter but would let me, personally, sleep better ;) I can't resist thinking there's a more JavaScript-aware solution to this, so consider all of these ugly workarounds ;)
If you came upon this question looking for a JS dictionary where objects are keys look at Map Map vs Object in JavaScript

Categories

Resources