Is a deep object slow in JavaScript? If so how much - javascript

Simple question: is there a merit of using a shallow object over a deeper one?
When I write a code, I tend to use a deep object just so it is easy to understand and classify. But I am wondering if this custom is making my code slower.
I have done a test but I have no idea if I am doing it correctly.
//building necessary objects
var a = {};
var b;
b = a;
for (var i = 0; i < 100; i++) {
b["a"] = {};
b = b["a"];
}
var c = {};
//objects used
//a.a.a. ..(101 "a"s).. .a === {}
//c === {}
//1st test: shallow
var d;
var start = performance.now();
for (var i = 0; i < 1000000000; i++) {
d = c;
d = null;
}
var end = performance.now();
console.log('Shallow: ' + (end - start));
//2nd test: deeper
var e;
var start = performance.now();
for (var i = 0; i < 1000000000; i++) {
e = a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a;
e = null;
}
var end = performance.now();
console.log('Deeper: ' + (end - start));
the result(ms):
shallow 3229 3304 3246 3253 3277
deep 3375 3343 3247 3193 3248
The test times for the deep object is not slow, but sometimes even faster than the shallow one.
Despite the result, I am not confident enough to conclude that they are the same speed.
Is there any difference between two of them?

You are using unrealistic code to test "real code", which is nonsense
You use Date.now() which is approximation to timestamp and you should use performance.now() to test js speed. Currently, even with good test code, you get wrong results.
JS engines are updating all the time. There were times when deep objects were slow, it's not a case anymore for the last x years. It's such an old problem that I can't even remember the years or google anything valuable out.

It is an optimisation in the js engine to access objects directly and allow for deep objects to be cashed in a variable which takes less time to reach. So it is faster to access them without having to go through the chain.
For example:
var a={a:{a:{}}}
var b=a.a.a
var c=b
// is faster than
var c=a.a.a
For more information read this: JavaScript Performance: Mutiple variables or one object?

Related

Is it worth it to convert array into set to search in NodeJS

I would like to know if it is worth to convert an array into a set in order to search using NodeJS.
My use case is that this search is done lot of times, but not necessary on big sets of data (can go up to ~2000 items in the array from time to time).
Looking for a specific id in a list.
Which approach is better :
const isPresent = (myArray, id) => {
return Boolean(myArray.some((arrayElement) => arrayElement.id === id);
}
or
const mySet = new Set(myArray)
const isPresent = (mySet, id) => {
return mySet.has(id);
}
I know that theoretically the second approach is better as it is O(1) and O(n) for the first approach. But can the instantiation of the set offset the gain on small arrays?
#jonrsharpe - particularly for your case, I found that converting an array of 2k to Set itself is taking ~1.15ms. No doubt searching Set is faster than an Array but in your case, this additional conversion can be little costly.
You can run below code in your browser console to check. new Set(arr) is taking almost ~1.2ms
var arr = [], set = new Set(), n = 2000;
for (let i = 0; i < n; i++) {
arr.push(i);
};
console.time('Set');
set = new Set(arr);
console.timeEnd('Set');
Adding element in the Set is always costly.
Below code shows the time required to insert an item in array/set. Which shows Array insertion is faster than Set.
var arr = [], set = new Set(), n = 2000;
console.time('Array');
for (let i = 0; i < n; i++) {
arr.push(i);
};
console.timeEnd('Array');
console.time('Set');
for (let i = 0; i < n; i++) {
set.add(i);
};
console.timeEnd('Set');
I run the following code to analyze the speed of locating an element in the array and set. Found that set is 8-10 time faster than the array.
You can copy-paste this code in your browser to analyze further
var arr = [], set = new Set(), n = 100000;
for (let i = 0; i < n; i++) {
arr.push(i);
set.add(i);
}
var result;
console.time('Array');
result = arr.indexOf(12313) !== -1;
console.timeEnd('Array');
console.time('Set');
result = set.has(12313);
console.timeEnd('Set');
So for your case array.some is better!
I will offer a different upside for using Set: your code is now more semantic, easier to know what it does.
Other than that this post has a nice comparison - Javascript Set vs. Array performance but make your own measurements if you really feel that this is your bottleneck. Don't optimise things that are not your bottleneck!
My own heuristic is a isPresent-like utility for nicer code but if the check is done in a loop I always construct a Set before.

V8 doesn't optimize function after 'manually' doing typed array .set()s

I have the following function (I'm posting it entirely because all the code parts might be relevant):
function buildUploadBuffers(cmds, len, vertexUploadBuffer, matrixUploadBuffer)
{
var vertexOffset = 0;
var matrixOffset = 0;
var quadLen = 24; //96 bytes for each quads, /4 since we're stepping 4 bytes at a time
var matLen = 16; //64/4, 4 rows of 4x floats with 4 bytes each, again stepping 4 bytes at a time
for (var i = 0; i < len; ++i)
{
var cmd = cmds[i];
var cmdQuads = cmd._numQuads;
var source = cmd._quadU32View;
var slen = cmdQuads * quadLen;
vertexUploadBuffer.set(source,vertexOffset);
vertexOffset += slen;
var mat = cmd._stackMatrixMat;
for(var j=0;j<cmdQuads * 4;++j)
{
matrixUploadBuffer.set(mat, matrixOffset);
matrixOffset += matLen;
}
}
}
It retrieves some typedArrays from each cmd in the cmds array and uses it to set values in some typedarray buffers.
This function is optimized fine, however, 'len' here is quite large and the data that is copied from the source typedArrays is quite small, and I have tested and profiled in the past that manually writing out the "set()"s can be significantly faster than relying on the compiler to optimize correctly. Further sometimes you can merge computations (such as here in the second loop because I copy the same thing 4 times to different places, but this is omitted in the following code since it doesn't change the results, for simplicity)
Doing this with the function above turns it into this:
function buildUploadBuffers(cmds, len, vertexUploadBuffer, matrixUploadBuffer)
{
var vertexOffset = 0;
var matrixOffset = 0;
var quadLen = 24; //96/4 since we're stepping 4 bytes at a time
var matLen = 16; //64/4
for (var i = 0; i < len; ++i)
{
var cmd = cmds[i];
var cmdQuads = cmd._numQuads;
var source = cmd._quadU32View;
var slen = cmdQuads * quadLen;
for(var j=0;j<slen; ++j)
{
vertexUploadBuffer[vertexOffset + j] = source[j];
}
vertexOffset += slen;
var mat = cmd._stackMatrixMat;
for(var j=0;j<cmdQuads * 4;++j)
{
for(var k=0;k<matLen; ++k)
{
matrixUploadBuffer[matrixOffset + k] = mat[k];
}
matrixOffset += matLen;
}
}
}
However, this second function is not optimized ("optimized too many times") despite doing essentially the same thing.
Running v8 with deopt traces produces the following suspicious statements (these are repeated several times in the output, until finally the compiler says no thanks and stops optimizing):
[compiling method 0000015F320E2B59 JS Function buildUploadBuffers
(SharedFunctionInfo 0000002ACC62A661) using Crankshaft OSR]
[optimizing 0000015F320E2B59 JS Function buildUploadBuffers
(SharedFunctionInfo 0000002ACC62A661) - took 0.070, 0.385, 0.093 ms]
[deoptimizing (DEOPT eager): begin 0000015F320E2B59 JS Function
buildUploadBuffers (SharedFunctionInfo 0000002ACC62A661) (opt #724)
#28, FP to SP delta: 280, caller sp: 0x2ea1efcb50]
;;; deoptimize at 4437: Unknown map in polymorphic access
So it seems that the deoptimization fails because of polymorphic access somewhere. Needless to say, the types contained in cmds are not always the same. They can be one of two concrete types that share the same prototype one step up the chain ('base class') where all the queried attributes come from (numQuads, quadU32View etc.).
Further
Why would it not just fail optimization with the first function that just uses .set() then? I'm accessing the same properties on the same objects. I'd think polymorphic access would break it in either case.
Type info of the function seems to be fine? When optimizing it the debug output says
ICs with typeinfo: 23/23 (100%), generic ICs: 0/23 (0%)]
Assuming there's nothing weird going on and the fact that the cmds can be one of two different types is indeed the culprit, how can I help out the optimizer here? The data in those cmds that I need from them is always the same, so there should be some way to package it up better for the optimizer, right? Maybe put a "quadData" object inside each cmd that contains numQuads, quadU32View, etc.? (just stabbing in the dark here)
Something that's very weird: Commenting out either of the two inner loops (or both at the same time of course) leads to the function getting optimized again. Is the function getting too long for the optimizer or something?
Because of the above point, I figured something might be weird with the (j) loop variable, so I tried using different ones for the different loops, which didn't change anything.
edit: Sure enough, the function optimizes again after I (e.g.) take out the second inner loop (uploading the matrix) and put it into a separate function. Interestingly enough this separate function is then seemingly inlined perfectly and I got the performance improvement I hoped for. Still makes me wonder what's going on here that prevents optimization. Just for completeness here's the thing that now optimizes well (and performs better, by about 25%):
function uploadMatrix(matrixUploadBuffer, mat, matLen, numVertices, matrixOffset)
{
for(var j=0;j<numVertices;++j)
{
for(var k=0;k<matLen; ++k)
{
matrixUploadBuffer[matrixOffset + k] = mat[k];
}
matrixOffset += matLen;
}
return matrixOffset;
}
function buildUploadBuffers(cmds, len, vertexUploadBuffer, matrixUploadBuffer)
{
var vertexOffset = 0;
var matrixOffset = 0;
var quadLen = 24; //96/4 since we're stepping 4 bytes at a time
var matLen = 16; //64/4
for (var i = 0; i < len; ++i)
{
var cmd = cmds[i];
var cmdQuads = cmd._numQuads;
var source = cmd._quadU32View;
var slen = cmdQuads * quadLen;
for(var j=0;j<slen; ++j)
{
vertexUploadBuffer[vertexOffset + j] = source[j];
}
vertexOffset += slen;
var mat = cmd._stackMatrixMat;
matrixOffset = uploadMatrix(matrixUploadBuffer,mat, matLen, cmdQuads *4, matrixOffset);
}
}

JavaScript - remove duplicates algorithm efficiency

I have read a lot about this topic and I saw many different algorithms. I have stumbled across another solution which Im having a hard time to understand its efficiency compared to other algorithms, since its using a simple temporary object to hold the existing elements of the array. Is that a valid solution compared to the "old school" method using a sophisticated sorting method and comparison?
function removeDup(arr){
var element,
existObj= {},
finalArr = [];
for(var i=0;i<arr.length;i++){
element = arr[i];
if(!existObj[element]){
finalArr.push(element);
existObj[element] = true;
}
}
return finalArr;
}
//console.log(removeDup([2,2,2,2,4534,5,7,3]));
console.log(removeDup(["mike","john","alex","mike","john"]));
A friend told me that the efficiency here cannot be clearly determined because i dont really know how was the temp object implemented.
You'll get the best performances by using most appropriate data structure. In a JIT/interpreted language like js, the gains of using a native functionality are tremendous.
Here it's a Set you should use in the first place : this way you don't even have to do anything to remove dups, they will just be ignored when added.
I just did a simple test, and performances are around six to ten times (!!) faster with a Set.
http://jsbin.com/jofofeyixaco/1/edit?js,console
result example :
"overhead is : 0.015700000221841037"
"Built unic numbers with a lookup object in : 6.237600000167731"
"Built unic numbers with a Set in : 0.7921500000520609"
Here are the curves for n = 0 to 50.000 for both algorithm.
We see that indeed the hashmap behaves quite like O(1), but with a higher spread when n raises.
Set is almost perfectly linear.
drawing jsbin (be patient ! ) : http://jsbin.com/jofofeyixaco/2/
Code :
// noprotect
// build a test set
var numbers = [];
var cnt = 10000;
for (var i=0; i<cnt; i++ ) numbers.push(Math.floor(Math.random*1000));
// build unic values using lookup object
function buildWithObject() {
var existing= {};
var unicNumbers = [];
for (var i=0; i<cnt; i++) {
var num = numbers[i];
if (!existing[num]) {
unicNumbers.push(num);
existing[num]=true;
}
}
}
// build unic values using a Set
function buildWithSet() {
var unicNumbersSet = new Set();
for (var i=0; i<cnt; i++) {
var num = numbers[i];
unicNumbersSet.add(num);
}
}
function iterate() {
for (var i=0; i<cnt; i++) {
var num = numbers[i];
}
}
// warming up functions
for (var i=0; i<30; i++) { buildWithObject(); buildWithSet() ; iterate(); }
// -------- Measures --------------------
var measureRepeat = 20;
var m;
var s,e;
// ----------------------------
m=measureRepeat;
s=window.performance.now();
while (m--) iterate();
e=window.performance.now();
console.log('overhead is : ' + (e-s)/measureRepeat);
// ----------------------------
m=measureRepeat;
s=window.performance.now();
while (m--) buildWithObject();
e=window.performance.now();
console.log('Built unic numbers with a lookup object in : ' + (e-s)/measureRepeat);
// ----------------------------
m=measureRepeat;
s=window.performance.now();
while (m--) buildWithSet();
e=window.performance.now();
console.log('Built unic numbers with a Set in : ' + (e-s)/measureRepeat);
(don't forget, Set is EcmaScript 6, so use, in the js tag, type="application/javascript;version=1.7"
If you're concerned about compatibility : http://kangax.github.io/compat-table/es6/#Set
All 'modern' platforms ok : Ch, FF, IE11, OS8
All others not ok. )
let existing = {};
let unicNumbers = [];
arr.forEach((item) => {
if (!existing[item.id]) {
unicNumbers.push(item);
existing[item.id] = true;
}
})

Javascript performance array of objects preassignment vs direct use

I have a doubt about how can be affected to speed the use of object data arrays, that is, use it directly or preasign them to simple vars.
I have an array of elements, for example 1000 elements.
Every array item is an object with 10 properties (for example).
And finally I use some of this properties to do 10 calculations.
So I have APPROACH1
var nn = myarray.lenght;
var a1,a2,a3,a4 ... a10;
var cal1,cal2,.. cal10
for (var x=0;x<nn;x++)
{ // assignment
a1=my_array[x].data1;
..
a10 =my_array[x].data10;
// calculations
cal1 = a1*a10 +a2*Math.abs(a3);
...
cal10 = (a8-a7)*4 +Math.sqrt(a9);
}
And APPROACH2
var nn = myarray.lenght;
for (var x=0;x<nn;x++)
{
// calculations
cal1 = my_array[x].data1*my_array[x].data10 +my_array[x].data2*Math.abs(my_array[x].data3);
...
cal10 = (my_array[x].data8-my_array[x].data7)*4 +Math.sqrt(my_array[x].data9);
}
Assign a1 ... a10 values from my_array and then make calculations is faster than make the calculations using my_array[x].properties; or the right is the opposite ?????
I dont know how works the 'js compiler' ....
The kind of short answer is: it depends on your javascript engine, there is no right and wrong here, only "this has worked in the past" and "this don't seem to speed thing up no more".
<tl;dr> If i would not run a jsperf test, i would go with "Cached example" 1 example down: </tl;dr>
A general rule of thumb is(read: was) that if you are going to use an element in an array more then once, it could be faster to cache it in a local variable, and if you were gonna use a property on an object more then once it should also be cached.
Example:
You have this code:
// Data generation (not discussed here)
function GetLotsOfItems() {
var ret = [];
for (var i = 0; i < 1000; i++) {
ret[i] = { calc1: i * 4, calc2: i * 10, calc3: i / 5 };
}
return ret;
}
// Your calculation loop
var myArray = GetLotsOfItems();
for (var i = 0; i < myArray.length; i++) {
var someResult = myArray[i].calc1 + myArray[i].calc2 + myArray[i].calc3;
}
Depending on your browser (read:this REALLY depends on your browser/its javascript engine) you could make this faster in a number of different ways.
You could for example cache the element being used in the calculation loop
Cached example:
// Your cached calculation loop
var myArray = GetLotsOfItems();
var element;
var arrayLen = myArray.length;
for (var i = 0; i < arrayLen ; i++) {
element = myArray[i];
var someResult = element.calc1 + element.calc2 + element.calc3;
}
You could also take this a step further and run it like this:
var myArray = GetLotsOfItems();
var element;
for (var i = myArray.length; i--;) { // Start at last element, travel backwards to the start
element = myArray[i];
var someResult = element.calc1 + element.calc2 + element.calc3;
}
What you do here is you start at the last element, then you use the condition block to see if i > 0, then AFTER that you lower it by one (allowing the loop to run with i==0 (while --i would run from 1000 -> 1), however in modern code this is usually slower because you will read an array backwards, and reading an array in the correct order usually allow for either run-time or compile-time optimization (which is automatic, mind you, so you don't need to do anything for this work), but depending on your javascript engine this might not be applicable, and the backwards going loop could be faster..
However this will, by my experience, run slower in chrome then the second "kinda-optimized" version (i have not tested this in jsperf, but in an CSP solver i wrote 2 years ago i ended caching array elements, but not properties, and i ran my loops from 0 to length.
You should (in most cases) write your code in a way that makes it easy to read and maintain, caching array elements is in my opinion as easy to read (if not easier) then non-cached elements, and they might be faster (they are, at least, not slower), and they are quicker to write if you use an IDE with autocomplete for javascript :P

What is the fastest / recommended way of creating new list with duplicate list entries in JavaScript?

My values naturally come in this form:
[1,2,3,4,5,6,7,8,9]
I am developing against a server api which requires an input parameter like:
[1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9]
Is there a faster or more js-style way to do than a simple for loop?
var f = function(values) {
var newList = [];
var i;
for (i = 0; i < values.length; i++) {
newList.push(values[i]);
newList.push(values[i]);
}
return newList;
}
You could avoid a .push() call by combining them since .push() is variadic.
newList.push(values[i], values[i]);
Other than that, I doubt you'll get much quicker.
You can use each function.
this will reduce your step.
var list=[1,2,3,4,5,6,7,8,9]
var newlist=[];
$.each(list,function(index,data){newlist.push(data);newlist.push(data)})
hope this helps.
May be assignment is faster...
L2 = [];
for (var i=L1.lenght*2; i-->0;) {
L2[i>>1] = L1[i];
}
but this kind of micro-optimization really needs to be profiled on the specific implementations (and I wouldn't be surprised in big differences between different Javascript engines).
I'd keep the most readable way unless this is a key issue (and if it's a key issue they probably Javascript is the wrong tool).
Try: [].concat.call([1,2,3,4,5,6,7,8,9],[1,2,3,4,5,6,7,8,9]).sort();
or more generic:
(function(){
return this.concat(this).sort(function(a,b){return a-b;});}
).call([1,2,10,20,30,40,50,60,70,80,9]);
or just a function:
function(v) {
var i = v.length, nw = [];
while (i--) { nw.push(v[i],v[i]); }
return nw.reverse();
}
or using map
var nw = ([1,2,3,4,5].map(function(a){this.push(a,a)},nw=[]),nw);
I suspect the function is the most efficient.

Categories

Resources