JS array length - when is it updated, when is it calculated? [duplicate] - javascript

What is the time complexity of a call to array.length in JavaScript? I think it would constant since it seems that property is set automatically on all arrays and you're just looking it up?

I think it would be constant since it seems that property is set automatically on all arrays and you're just looking it up?
Right. It's a property which is stored (not calculated) and automatically updated as necessary. The specification is explicit about that here and here amongst other places.
In theory, a JavaScript engine would be free to calculate length on access as though it were an accessor property as long as you couldn't tell (which would mean it couldn't literally be an accessor property, because you can detect that in code), but given that length is used repeatedly a lot (for (let n = 0; n < array.length; ++n) springs to mind), I think we can assume that all JavaScript engines in widespread use do what the spec says or at least something that's constant time access.
Just FWIW: Remember that JavaScript's standard arrays are, in theory, just objects with special behavior. And in theory, JavaScript objects are property bags. So looking up a property in a property bag could, in theory, depend on how many other properties are there, if the object is implemented as some kind of name->value hashmap (and they used to be, back in the bad old days). Modern engines optimize objects (Chrome's V8 famously creates dynamic classes on the fly and compiles them), but operations on those objects can still change property lookup performance. Adding a property can cause V8 to create a subclass, for instance. Deleting a property (actually using delete) can make V8 throw up its hands and fall back into "dictionary mode," which substantially degrades property access on the object.
In other words: It may vary, engine to engine, even object to object. But if you use arrays purely as arrays (not storing other non-array properties on them), odds are you'll get constant-time lookup.

It doesn't seem like a bottleneck but if you want to be sure use var len = arr.length and check that. It doesn't hurt and seems to be a tad faster on my machine albeit not a significant difference.
var arr = [];
for (var i = 0; i < 1000000; i++) {
arr[i] = Math.random();
}
var start = new Date();
for (var i = 0; i < arr.length; i++) {
arr[i] = Math.random();
}
var time1 = new Date() - start;
var start = new Date();
for (var i = 0, len = arr.length; i < len; i++) {
arr[i] = Math.random();
}
var time2 = new Date() - start;
document.getElementById("output").innerHTML = ".length: " + time1 + "<br/>\nvar len: " + time2;
<div id="output"></div>

Related

Attribute vs constant access in javascript

I'm working on High-performance oriented web components and I doubt if it's worths assign an object attribute's value to a constant before accessing it multiple times.
I mean turning this:
let counter = 0;
for (let i = 0, len = parentObject.myObject.items.length; i < len; i++) {
// items is an array of integers
counter += parentObject.myObject.items[i] ;
}
Into this:
let counter = 0;
const { myObject } = parentObject;
const { items } = myObject;
for (let i = 0, len =items.length; i < len; i++) {
counter += items[i] ;
}
In Python this change would have a sentitive impact in performance. However the tests I have made (code at https://gist.github.com/Edorka/fbfb0778c859d8f518f0508414d3e6a2) shows no difference:
caseA total 124999750000
Execution time (hr): 0s 1.88101ms
caseB total 124999750000
Execution time (hr): 0s 1.117547ms
I doubt if I'm making my tests wrong or if the VM has any optimization for this case I'm not aware of.
UPDATE: Following #George Jempty suggestion I made a quick adaptation on JSPerf at https://jsperf.com/attribute-vs-constants but results keep being quite erratic.
Nested property access is one of the most frequently executed operation in JavaScript. You can expect it to be heavily optimized.
Indeed, the V8 engine caches object properties at run time, so the performance benefit of caching manually would be negligible.
Live demo on jsperf.com
Conclusion: don't worry about it!

Performance of array includes vs mapping to an Object and accessing it in JavaScript

According to the fundamentals of CS
the search functionality of an unsorted list has to occur in O(n) time where as direct access into an array will occur in O(1) time for HashMaps.
So is it more performant to map an array into a dictionary and then access the element directly or should I just use includes? This question is specifically for JavaScript because I believe this would come down to core implementation details of how includes() and {} is implemented.
let y = [1,2,3,4,5]
y.includes(3)
or...
let y = {
1: true,
2: true
3: true
4: true
5: true
}
5 in y
It's true that object lookup occurs in constant time - O(1) - so using object properties instead of an array is one option, but if you're just trying to check whether a value is included in a collection, it would be more appropriate to use a Set, which is a (generally unordered) collection of values, which can also be looked up in linear time. (Using a plain object instead would require you to have values in addition to your keys, which you don't care about - so, use a Set instead.)
const set = new Set(['foo', 'bar']);
console.log(set.has('foo'));
console.log(set.has('baz'));
This will be useful when you have to look up multiple values for the same Set. But, adding items to the Set (just like adding properties to an object) is O(N), so if you're just going to look up a single value, once, there's no benefit to this nor the object technique, and you may as well just use an array includes test.
Updated 04/29/2020
As the commenter rightly pointed out it would seem V8 was optimizing out the array includes calls. An updated version that assigns to a var and uses it produces more expected results. In that case Object address is fastest, followed by Set has and in a distant third is Array includes (on my system / browser).
All the same, I do stand by my original point, that if making micro-optimizations it is worth testing assumptions. Just make sure your tests are valid ;)
Original
Well. Despite the obvious expectation that Object address and Set has should outperform Array includes, benchmarks against Chrome indicate that implementation trumps expectation.
In the benches I ran against Chrome Array includes was far and away the best performer.
I also tested locally with Node and got more expected results. In that Object address wins, followed closely by Set has, then Array includes was marginally slower than both.
Bottom line is, if you're making micro-optimizations (not recommending that) it's worth benchmarking rather than assuming which might be best for your particular case. Ultimately it comes down to the implementation, as your question implies. So optimizing for the target platform is key.
Here's the results I got:
Node (12.6.0):
ops for Object address 7804199
ops for Array includes 5200197
ops for Set has 7178483
Chrome (75.0):
https://jsbench.me/myjyq4ixs1/1
This isn't necessarily a direct answer to the question but here is a related performance test I ran real quick in my chrome dev tools
function getRandomInt(max) {
return Math.floor(Math.random() * max);
}
var arr = [1,2,3];
var t = performance.now();
for (var i = 0; i < 100000; i++) {
var x = arr.includes(getRandomInt(3));
}
console.log(performance.now() - t);
var t = performance.now();
for (var i = 0; i < 100000; i++) {
var n = getRandomInt(3);
var x = n == 1 || n == 2 || n == 3;
}
console.log(performance.now() - t);
VM44:9 9.100000001490116
VM44:16 5.699999995529652
I find the array includes syntax nice to look at, so I wanted to know if the performance was likely to be an issue the way I use it, for checking if a variable is one of a set of enums for instance. It doesn't seem to be much of an impact for situations like this with a short list. Then I ran this.
function getRandomInt(max) {
return Math.floor(Math.random() * max);
}
var t = performance.now();
for (var i = 0; i < 100000; i++) {
var x = [1,2,3].includes(getRandomInt(3));
}
console.log(performance.now() - t);
var t = performance.now();
for (var i = 0; i < 100000; i++) {
var n = getRandomInt(3);
var x = n == 1 || n == 2 || n == 3;
}
console.log(performance.now() - t);
VM83:8 12.600000001490116
VM83:15 4.399999998509884
and so the way I actually use it and like lookin at it is quite worse with performance, despite still not being very significant unless run a few million times, so using it inside of an Array.filter that may run a lot as a react redux selector may not be a great idea like I was about to do when I decided to test this.

Preventing Java Nashorn from super excessive memory usage when dynamically creating a map

This trivial code, when running with Nashorn, causes full GCs
var x = {};
for (var i = 0; i < 10000; i++) {
var key = "key-" + i;
x[key] = i;
}
Reading through the Nashorn implementation, I believe each addition to an Object (using PropertyMap class) clones an object, adds the new key, links it to the previous version's "history" as a weak reference, and so on and so on.
This makes the code above quadratic in both memory and time.
Any ideas how to avoid it?
Your analysis is correct, Nashorn objects and property maps do not currently scale to lots of properties. The reason for making PropertyMap immutable is to allow quick validation of inline callsites by comparing PropertyMap references.
One solution would be to switch to per-ScriptObject, mutable property maps when the number of properties exceeds some threshold. We might implement this in a future version of Nashorn, but I can't make any promises right now.
As a workaround, you could use Java Maps for storing larger amounts of key-value pairs. Also, in JDK 9 Nashorn will get some ECMAScript 6 features which include the new Map, Set, WeakMap and WeakSet collections.
Have you tried using prototypes?
I am not sure (didn't work with Nashorn), but maybe this could help you:
var x = function() {};
for (var i = 0; i < 10000; i++) {
var key = "key-" + i;
x.prototype[key] = i;
}
console.log(new x());

Javascript: Is the length method efficient?

i'm doing some javascript coding and I was wondering if the length method is "precomputed", or remembered by the JS engine.
So, the question is:
If I'm checking really often for an array length, and supposing that i'm not changing it (making it immutable through a closure), should I precompute the length method and store it in some variable?
Thanks!
As always, the answer is "it depends".
Let's test native arrays with a million-element array:
for (var i = 0; i < arr.length; i++);
var len=arr.length;
for (var i = 0; i < len; i++);
http://josh3736.net/images/arrlen.png
Chrome and Firefox optimize the property accessor to be as efficient as copying the length to a local variable. IE and Opera do not, and are 50%+ slower.
However, keep in mind that the test results' "ops/second" means number of complete iterations through an array of one million elements per second.
To put this in perspective, even in IE8 (the worst performer in this bunch)—which scored .44 and 3.9 on property access and local variable (respectively)—the per-iteration penalty was a scant 2 µs. Iterating over a thousand items, using array.length will only cost you an extra 2 ms. In other words: beware premature optimization.
The length of an actual array is not computed on the fly. It's stored as part of the array data structure so accessing it involves no more work than just fetching the value (there is no computation). As such, it will generally be as fast as retrieving any fixed property of an object. As you can see in this performance test, there is basically no difference between retrieving the length of an array and retrieving a property of an object:
http://jsperf.com/length-comparisons
An exception to this is the nodeList objects that the DOM returns from functions like getElementsByTagName() or getElementsByClassName(). In these, it is often much slower to access the length property. This is probably because these nodeList objects are not true javascript objects and there may be a bridge between Javascript and native code that must be crossed each time something is accessed from these objects. In this case, it would be a LOT faster (10-100x faster) to cache the length into a local variable rather than use it repeatedly in a loop off the nodeList. I've added that to the length-comparison and you can see how much slower it is.
In some browsers, it is meaningfully faster to put the length into a local variable and use it from there if you will be referring to it over and over again (like in a loop). Here's the performance graph from the above jsperf test:
All major interpreters provide efficient accessors for the lengths of native arrays, but not for array-like objects like NodeLists.
"Efficient looping in Javascript"
Test / Browser Firefox 2.0 Opera 9.1 Internet Explorer 6
Native For-Loop 155 (ms) 121 (ms) 160 (ms)
...
Improved Native While-Loop 120 (ms) 100 (ms) 110 (ms)
"Efficient JavaScript code" suggests
for( var i = 0; i < document.getElementsByTagName('tr').length; i++ ) {
document.getElementsByTagName('tr')[i].className = 'newclass';
document.getElementsByTagName('tr')[i].style.color = 'red';
...
}
var rows = document.getElementsByTagName('tr');
for( var i = 0; i < rows.length; i++ ) {
rows[i].className = 'newclass';
rows[i].style.color = 'red';
...
}
Neither of these are efficient. getElementsByTagName returns a dynamic object, not a static array. Every time the loop condition is checked, Opera has to reassess the object, and work out how many elements it references, in order to work out the length property. This takes a little more time than checking against a static number.
There's probably a modest speed boost attainable by caching the length in a local variable due to attribute lookup speed. This may or may not be negligible, depending on how the JS engine JITs the code.
See http://jsperf.com/for-loop-caching for a rudimentary JSperf testcase.
For any collection-type object whose length you will not be manipulating (e.g. any immutable collection), it's always a good idea to cache its length for better performance.
var elems = document.getElementsByName("tst");
var elemsLen = elems.length;
var i;
for(i = 0; i < elemsLen; ++i)
{
// work with elems... example:
// elems[i].selected = false;
}
elems = [10,20,30,40,50,60,70,80,90,100];
elemsLen = elems.length;
for(i = 0; i < elemsLen; ++i)
{
// work with elems... example:
// elems[i] = elems[i] / 10;
}

Do loops check the array.length every time when comparing i against array.length?

I was browsing around and I found this:
var i, len;
for(i = 0, len = array.length; i < len; i++) {
//...
}
My first thoughts are:
Why he did that? (it must be better for some reason)
Is it worth it? (I assume yes, why else he will do it this way?)
Do normal loops (the ones that don't cache the length) check the array.length each time?
A loop consisting of three parts is executed as follows:
for (A; B; C)
A - Executed before the enumeration
B - condition to test
C - expression after each enumeration (so, not if B evaluated to false)
So, yes: The .length property of an array is checked at each enumeration if it's constructed as for(var i=0; i<array.length; i++). For micro-optimisation, it's efficient to store the length of an array in a temporary variable (see also: What's the fastest way to loop through an array in JavaScript?).
Equivalent to for (var i=0; i<array.length; i++) { ... }:
var i = 0;
while (i < array.length) {
...
i++;
}
Is it worth it? (obviously yes, why else he will do it this way?)
Absolutely yes. Because, as you say, loop will calculate array length each time. So this will cause an enormous overhead. Run the following code snippets in your firebug or chrome dev tool vs.
// create an array with 50.000 items
(function(){
window.items = [];
for (var i = 0; i < 50000; i++) {
items.push(i);
}
})();
// a profiler function that will return given function's execution time in milliseconds
var getExecutionTime = function(fn) {
var start = new Date().getTime();
fn();
var end = new Date().getTime();
console.log(end - start);
}
var optimized = function() {
var newItems = [];
for (var i = 0, len = items.length; i < len; i++) {
newItems.push(items[i]);
}
};
var unOptimized = function() {
var newItems= [];
for (var i = 0; i < items.length; i++) {
newItems.push(items[i]);
}
};
getExecutionTime(optimized);
getExecutionTime(unOptimized);
Here is the approximate results in various browsers
Browser optimized unOptimized
Firefox 14 26
Chrome 15 32
IE9 22 40
IE8 82 157
IE7 76 148
So consider it again, and use optimized way :)
Note: I tried to work this code on jsPerf but I couldn't access jsPerf now. I guess, it is down when I tried.
I always thought in JavaScript length was just a property of the array object, pre-calculated by previous array operations - creation, addition, removal - or overridden by the user, so you're just looking up a variable anyway? I must admit I had just assumed that because of the lack of parenthesis, but looking at the MDN page for array.length, it seems to say the same thing.
In languages where length is a method or length is calculated by a standard library function, then you should pre-calculate the length before running the loop so The array isn't calculated every iteration, particularly for large datasets. Even then, in modern high level languages like Python, len() just returns the length property of the array object anyway.
So unless I'm mistaken, the complexity is just O(1), and from that standpoint, even if the variable were slightly faster than a property to lookup each pass, it wouldn't be worth the potential trouble of creating/reusing additional variables outside of the protective for loop scope.
However, I suspect that in this case the reason the example's programmer chose this approach is simply just a habit they picked up in another language and carried forwards JavaScript.
One reason to do this is say, if you're adding elements to the array during the loop but do not want to iterate over them. Say you want to turn [1, 2, 3] into [1, 2, 3, 1, 2, 3]. You could to that with:
var initialLength = items.length;
for(var i=0; i<initialLength; ++i) {
items.push(items[i]);
}
If you don't save the length before the loop, then array.length will keep increasing and the loop will run until the browser crashes / kills it.
Other than that, as the others said, it mildly affects performance. I wouldn't make a habit out of doing this because "premature optimization is the root of all evil". Plus, if you change the size of the array during the loop, doing this could break your code. For instance, if you remove elements from the array during the loop but keep comparing i to the previous array size, then the loop will try to access elements beyond the new size.
Yes
Its check the array.length every time, but if we don't want to run our loop for increased array then, in that case, we can use forEach method.
forEach is a javascript in build method which is does like for loop, but forEach only iterative the elements in an array which are before the loop start.
Let's understand this from below snippet:
array = [1,2,3,4]
for(i=0;i<=array.length;i++){
console.log(array[i]);
array.push(array[i]+1);
}
output like
1
2
3
4
5
6
...so on (infinite) while its checking array.length each time
let's check with forEach method
array = [1,2,3,4]
array.forEach((element) => {
console.log(element);
array.push(element+1);
})
console.log("array elements after loop",array);
it only processes for 4 elements which are present in array before iteration start.
**but in forEach case, it will affect on array.length if we pop out the element from array.
lets see this by an example:
array = [1,2,3,4]
array.forEach((element) => {
console.log(element);
array.pop()
})
console.log("array elements after loop",array);
Here are a number of performance tests for different approaches
http://www.websiteoptimization.com/speed/10/

Categories

Resources