Why does console.time show much lower time than the actual time? - javascript

I am testing a snippet of JavaScript's speed using the console.time(); method in Chrome and Chromium-based Edge. When I'm running the snippet in the browser, it takes at least 2 seconds, but the displayed result of time is around milliseconds, What is happening here?
var list = [...Array(50000000).keys()];
console.time("time");
var x = 0;
for (let i = 0, n= list.length; i<n ;i++) {
x++;
}
console.timeEnd("time");
I've tested this with performance.now() and I get the same result as time, which is really confusing however it works perfectly fine in Firefox.
Is this a Chrome/Edge bug? if it is, How can one submit an issue for chrome?
Update
Thanks to #vlaz and #Jax-p I found out that I've missed the array generation time:
console.time("time");
var list = [...Array(50000000).keys()];
var x = 0;
for (let i = 0, n= list.length; i<n ;i++) {
x++;
}
console.timeEnd("time");

Creating and spearding array with [...Array(50000000).keys()]; takes over 1.5s in my Chrome but you have timer start after that (You had. Before you change the question.). I am getting same (a little bit higher) results in Firefox. Can it be it?
Suppose there is also a delay before the browser even gets to execute JavaScript.
console.time("time");
var list = [...Array(50000000).keys()];
console.timeEnd("time");
console.time("time2");
var x = 0;
for (let i = 0, n= list.length; i<n ;i++) {
x++;
}
console.timeEnd("time2");

Related

Why is using find() on these arrays so slow when within a for loop?

Background: I came across this issue whilst dealing with arrays of large and small numbers using the findIndex function. I have given a minimum working example below. I can avoid the issue, but I just don't understand why the issue exists in the first place.
In node.js (v12.16.3), why does getting rid of the for loop around the find function in this example cause the performance to increase dramatically? (5600 ms reduced to 250 ms)
The issue does not appear if I change the value in the second array from 1e10 to 1e9 or less, or if I change the value in the first array from 1 to 1e10 or more.
const nSims = 1e8
const arrays = [];
arrays[0] = [1];
arrays[1] = [1e10];
console.time('a')
for (var i = 0; i < nSims; i++) {
for (var j = 0; j < 2; j++) {
arrays[j].find((value) => value > 0);
}
}
console.timeEnd('a') // 5600 ms
console.time('b')
for (var i = 0; i < nSims; i++) {
arrays[0].find((value) => value > 0);
arrays[1].find((value) => value > 0);
}
console.timeEnd('b') // 250 ms
V8 developer here.
The "slow case" is the true cost of calling Array.find with a callback: for every element, the built-in implementation of Array.find performs a call to the provided callback. Aside from doing this basic work that you asked it to do, the implementation is actually pretty optimized, both the Array.find built-in and the supplied callback.
The fast case benefits from certain additional optimizations in V8: if a call to Array.find has only ever seen arrays of the same type (including internal representation, see below), then there's some special handling in the type feedback collection system and the optimizing compiler to emit a special inlined version of it, which in particular has the follow-on benefit that it can also inline the provided callback, specialized for this type of array. As you can see here, this optimization provides a massive speed boost when it is applicable.
The reason that [1e9] and [1e10] are different types of arrays under the hood is because 1e9 is a 30-bit integer, so V8 internally chooses "small integer" (aka "smi", 31-bit signed int) representation for the array's elements. 1e10, however, would require 34 bits, so V8 chooses double (64-bit floating point) representation for the array elements. So if the same occurrence of Array.find encounters both [1e9] (or [1] for that matter) and [1e10], it decides "I've seen more than one type of array here, inlining more than one special case probably costs more than it's worth, let's use the generic version". You could say that this decision is a bit overly pessimistic in this case, but such is the nature of heuristics: engines need rules to decide what to do, and since they can't predict what your code will do in the future, they just have to make some guess -- which could turn out to be a good guess, or a not so good guess :-)
It's not related to having a loop per se; looping over the list of arrays is just one way of making the same Array.find encounter several array types. You could trigger the fallback to the generic path without a loop by using a function that's called with different inputs; or you could have a loop (that loops over something else) while still staying on the fast path.
#Anton wrote:
It seems, that find method has some problems.
I wouldn't put it that way. It's not easy for an engine to optimize Array.find to the same degree as a hand-written for-loop -- for instance, because an engine generally can't inline user-provided callbacks into built-in functions. As explained above, V8 knows enough tricks to be able to pull off such inlining in some situations, but not always.
This is far from the only case where a hand-written replacement for a built-in function can achieve faster performance; in many cases this is because the built-in functions are more general (i.e.: support more weird corner cases) than the hand-written replacement. It's also the case that outside of targeted microbenchmarks it is fairly rare (though certainly not impossible) to find a case where these differences actually matter.
Note: Maybe this is not the correct answer, but it is just a very big comment (I need code snippets to illustrate).
This is example from the question (it takes more that 5 seconds for the a, and less than second for b):
const nSims = 1e8
const arrays = [];
arrays[0] = [1];
arrays[1] = [1e10];
console.time('a')
for (var i = 0; i < nSims; i++) {
for (var j = 0; j < 2; j++) {
arrays[j].find((value) => value > 0);
}
}
console.timeEnd('a') // 5600 ms
console.time('b')
for (var i = 0; i < nSims; i++) {
arrays[0].find((value) => value > 0);
arrays[1].find((value) => value > 0);
}
console.timeEnd('b') // 250 ms
This happens if we change 1e10 to 1e9 ("magic" here):
const nSims = 1e8
const arrays = [];
arrays[0] = [1];
arrays[1] = [1e9];
console.time('a')
for (var i = 0; i < nSims; i++) {
for (var j = 0; j < 2; j++) {
arrays[j].find((value) => value > 0);
}
}
console.timeEnd('a') // 5600 ms
console.time('b')
for (var i = 0; i < nSims; i++) {
arrays[0].find((value) => value > 0);
arrays[1].find((value) => value > 0);
}
console.timeEnd('b') // 250 ms
It seems, that find method has some problems. Here what happens if we replace it with for iteration (a and b becomes close, and less than 1 second):
const nSims = 1e8
const arrays = [];
arrays[0] = [1];
arrays[1] = [1e10];
function find(arr) {
for (let i = 0; i < arr.length; i++) {
if (arr[i] > 0) return arr[i];
}
}
console.time('a')
for (var i = 0; i < nSims; i++) {
for (var j = 0; j < 2; j++) {
find(arrays[j]);
}
}
console.timeEnd('a')
console.time('b')
for (var i = 0; i < nSims; i++) {
find(arrays[0]);
find(arrays[1]);
}
console.timeEnd('b')

What happens if you put an iteration count of a for loop as a variable?

I want to make a program in javascript in which a person inputted the iteration count for a for loop(they could input x++, or y--), but I don't know if I am using the right method.
Here is my code:
var x = prompt("iteration count")
// x should equal something like, i++, or x--
for(var i = 0; i < 10; x){
document.write(i)
}
But when the code ran the program kept crashing.
Why is it crashing and how do I fix this?
Please Help
you need to parse the int value of x because it's a string and use it to increment i
var x = parseInt(prompt("iteration count"))
for (var i = 0; i < 10; i += x) {
document.write(i)
}
EDIT :
based on the question edit and the comments, you can use eval(), but :
Do not ever use eval!
eval() is a dangerous function, which executes the code it's passed with the privileges of the caller.
So before you use it, read the MDN page and check : eval isnt evil it's just misunderstood
where there's this comment from Spudley :
From a security perspective, eval() is far more dangerous in a server
environment, where code is expected to be fully trusted and hidden
from the end user.
In a browser, the user could eval any code they wanted at any time
simply by opening dev tools, so as a developer you can't get away with
having anything on your client code that could be insecure against
eval anyway.
to test the snippet below, type i++ in the prompt
var x = prompt("iteration count");
for (var i = 0; i < 10; eval(x)) {
console.log(i)
}
an alternative to eval() would be new Function or check the answers here : Programatically setting third statement of for loop
var input = 'i++';//Or whatever condition user passing in
var conditionProgramatically = () => new Function(input)() ;
for (var i = 0; i < 10; conditionProgramatically()) {
console.log(i)
}
For for-loop, third statement will be invoked/executed on every iteration, and hence we set a function call, and in that function, we execute whatever user passing in as you've mentioned i++
That is an endless loop because the variable i never incremented. Try this one.
var x = prompt("iteration count")
for(var i = 0; i < x, i++){
document.write(i)
}
You forgot to increment the index variable, it result to endless loop and maximum stack error, you can also use + for parseInt shorcut.
var x = +prompt("iteration count")
for(var i = 0; i < x;i++){
document.write(i)
}
You have to parse the input value and then make it as a condition to stop iterating after the given value.
var x = parseInt(prompt("iteration count"))
for (var i = 0; i < x; i++) {
document.write(i);
}

Optimizing a for loop in JS (push inside)

I have the following loop. The length is around 1500 points. But this snippit might get called multiple times on a page load (6-7).
buffer[xname] = [xname];
buffer[yname] = [yname];
for (var i = 0; i < rawdata.length; i++) {
buffer[xname].push( rawdata[i][0] );
buffer[yname].push( rawdata[i][1] );
}
I need to do this operation in the browser (it is used to condition the data before plotting them).
Currently this makes the browser very slow.
I tried to use a setTimeout() to ease the event loop a bit. That works but it takes seconds.
Is there any way to make this loop faster? Maybe some sort of mapping?
You can reduce the loop to half by doing:
buffer[xname] = [xname];
buffer[yname] = [yname];
var dataLength = rawdata.length;
for (var i = 0; i < dataLength / 2; i++) {
buffer[xname][i] = rawdata[i][0];
buffer[yname][i] = rawdata[i][1];
buffer[xname][dataLength - i -1] = rawdata[dataLength - i -1][0];
buffer[yname][dataLength - i -1] = rawdata[dataLength - i -1][1];
}
Not sure if the change between using push or direct assignment would impact enough to make the execution time the same.
Thanks to #royhowie
Why is array.push sometimes faster than array[n] = value?
If you have control over the source of rawdata, you might want to consider changing it so it can be used without additional processing.

Slowing Down JavaScript Loop

I have a piece of JavaScript that generates every possible combination of a charset for the length provided. Since I'm using it for a length of 12, it's a very long loop that freezes and crashes the browser.
I've tried replacing the for loop with a setInterval() but it only seemed to break it.
How can I slow down my loop?
Here's the script:
var charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890',
charset_length = charset.length;
function recurse(width, pos, base) {
for (var i = 0; i < charset_length; i++) {
if (pos < width - 1) {
recurse(width, pos+1, base + charset[i]);
}
console.log(base + charset[i]); // replaced later
}
}
recurse(12, 0, '');
EDIT: Because each output will open a new tab (that will close itself once done), I want to slow it down so a maximum of 5 tabs approx. are open at the same time.

javascript issue undefined variable in array

Can someone please tell me what's wrong with this code? Chrome and Firefox are saying that scrns[i] is undefined though Chrome still runs the code on mouseover.
function nextPrev() {
if (!document.getElementsByClassName) return false;
var scrns = document.getElementsByClassName('scrn');
for (var i=0; i<=scrns.length; i++) {
// console.log(i);
scrns[i].onmouseover = function() {
// console.log('foo');
}
}
}
window.onload = nextPrev();
I've tested that the for loop is working and tried to pin down where the problem is coming from in every way I know how. I'm even looking at an example I took from a book sometime ago and cannot understand why scrns[i] would be undefined.
Any help greatly appreciated!
You're using <= when looping through. But remember that arrays are indexed starting at 0, not 1. So an array with 10 elements has a length of 10, but elements 0-9. Change the following:
for (var i=0; i<=scrns.length; i++) {
to:
for (var i=0; i < scrns.length; i++) {
You are looping too far. If i is equal to scrns.length then it is beyond the end of the array. Remove the = in your stop condition:
for (var i=0; i < scrns.length; i++) {
You have an off by one error. Changing <= to < should fix your issue. You can use loop invariants in the future to make sure that you don't go over.
http://en.wikipedia.org/wiki/Loop_invariant
In general though, when looping through an array, begin with the iterating counter at 0 and then loop so long as the counter is less than the length of the array.

Categories

Resources