'use strict'
function test() {
let t = Date.now();
let p = 0;
for (let i = 0; i < 100000000; i++) {
p += i % 2;
}
console.log(p)
console.log('test: ', Date.now() - t);
}
function test1() {
var t = Date.now();
var p = 0;
for (var i = 0; i < 100000000; i++) {
p += i % 2;
}
console.log(p)
console.log('test1 : ', Date.now() - t);
}
test();
test1();
run the code above in chrome, why test1 is fast than test. is the let' fault or my fault?
50000000
test: 1146
50000000
test1 : 148
It might be worth mentioning that in es6 the let keyword in a for-loop has been designed to solve the notorious closure in a loop problem in JavaScript:
var log = msg => div.innerHTML += msg + "<br>";
for (var i=0; i < 3; i++) {
Promise.resolve().then(() => log(i)); // 3, 3, 3
}
for (let i=0; i < 3; i++) {
Promise.resolve().then(() => log(i)); // 0, 1, 2
}
<div id="div"></div>
As #loganfsmyth mentions in comments, it does this by effectively creating a new closure for each iteration of the loop.
This, and the fact that the feature is new, might account for some of the performance difference seen in Chrome. That said, there seems to be no difference in Firefox for your particular example, so it seems possible for browsers to optimize this.
Related
So, in this code I have a string of 0's and 1's and the length of the string is 32, which will be split in 6 equal parts but the last part will have the length of 2 so I will add (4) 0's after that which will make its length 6. So I wrote a function that will add the remaining 0's which is padding(num).
And that function will be invoked in side the slicing(str) function.
But the code breaks when I try to do execute.
Any help?
Thanks.
// This code works.
function padding0s(num) {
let s = "";
for (i = 0; i < 6 - num; i++) {
s += "0";
}
return s;
}
function slicing(str) {
let k = 6;
let res = [];
let temp1 = 0;
let f = padding0s(2);
for (i = 0; i < str.length; ) {
res.push(str.slice(i, k));
i += 6;
k += 6;
if (res[temp1].length !== 6) {
res[temp1] += f;
}
temp1++;
}
console.log(res);
}
slicing("01000011010011110100010001000101");
// But this does not..
function padding0s(num) {
let s = "";
for (i = 0; i < 6 - num; i++) {
s += "0";
}
return s;
}
function slicing(str) {
let k = 6;
let res = [];
let temp1 = 0;
for (i = 0; i < str.length; ) {
res.push(str.slice(i, k));
i += 6;
k += 6;
if (res[temp1].length !== 6) {
let f = padding0s(res[temp1].length);
res[temp1] += f;
}
temp1++;
}
console.log(res);
}
slicing("01000011010011110100010001000101");
Always define variables before using them
Not doing so can result in undefined behaviour, which is exactly what is happening in your second case. Here is how:
for (i = 0; i < str.length; ) {...}
// ^ Assignment to undefined variable i
In the above for-loop, by using i before you define it, you are declaring it as a global variable. But so far, so good, as it doesn't matter, if not for this second problem. The real problem is the call to padding0s() in your loop. Let's look at padding0s:
function padding0s(num) {
...
for (i = 0; i < 6 - num; i++) {
s += "0";
}
}
This is another loop using i without defining it. But since i was already defined as a global variable in the parent loop, this loop will be setting its value. So in short, the value of i is always equal to 6 - num in the parent loop. Since your exit condition is i < str.length, with a string of length 32 the loop will run forever.
You can get around this in many ways, one of which you've already posted. The other way would be to use let i or var i instead of i in the parent loop. Even better is to write something like this (but beware that padEnd may not work on old browsers):
function slicing(str) {
return str.match(/.{1,6}/g).map((item) => {
return item.padEnd(6, "0");
});
}
console.log(slicing("01000011010011110100010001000101"));
class Obj {
constructor() {
this.propA = ~~(Math.random() * 255 + 0.5);
this.propB = ~~(Math.random() * 300 + 0.5);
}
}
const arr1 = new Array(100000);
for (var i = 0; i < 100000; i ++) {
arr1[i] = new Obj();
}
function test1() {
let start = new Date();
for (var times = 0; times < 1000; times ++) {
let n = 0;
for (var i = 0; i < 100000; i++) {
if (arr1[i].propA > arr1[i].propB) {
n += 1;
//arr1[i].propB = arr1[i].propA; //<-- try uncomment it
}
}
}
console.log(new Date() - start + 'ms');
}
test1();
paste this code to developer tools(or a new .html file).
on my computer(win7 x64, chrome 63) it prints 1200-1600ms.
however when I uncomment the code it prints only 500-700ms.
I don't know why it happens...
I don't know why it happens...
Because after firs time when
arr1[i].propB = arr1[i].propA;
has been executed, from the next iteration
if (arr1[i].propA > arr1[i].propB)
will be false and hence that line n += 1; will not get executed.
Since you are saving one operations by replacing increment and assignment with only assignment, you see a improvement in speed.
Given:
(function() {
var items = [1, 2, 3, 4];
// In Chrome, this takes ~8-10 ms to execute.
for(var i = 0; i < items.length; i++) {
x(items);
}
// In Chrome, this takes 1-2 ms to execute.
for(var i = 0; i < items.length; i++) {
y();
}
function x(y) {
y[0] = -100;
}
function y() {
items[0] = 100;
}
})();
Why are the calls to x() 8-10 times slower than the calls to y()? Is it because variable resolution does not need to take place in the execution of y()?
I'm not seeing a difference in time except for the first iteration or 2 which suggests that there is no big difference except something getting added during start up. V8 doesn't optimize immediately AFAIK so that could explain why it takes a few iterations to balance out. Also cache misses.
function log() {
var div = document.createElement("div");
div.textContent = Array.prototype.join.call(arguments, " ");
document.body.appendChild(div);
};
(function() {
var items = new Array(10000000);
for (j = 0; j < 20; ++j) {
var xStart = performance.now();
for(var i = 0; i < items.length; i++) {
x(items);
}
var xDuration = performance.now() - xStart;
var yStart = performance.now();
for(var i = 0; i < items.length; i++) {
y();
}
var yDuration = performance.now() - yStart;
log(j, "x:", xDuration.toFixed(3) + "ms",
"y:", yDuration.toFixed(3) + "ms",
"diff:", (xDuration - yDuration).toFixed(3) + "ms");
}
function x(y) {
y[0] = -100;
}
function y() {
items[0] = 100;
}
})();
body { font-family: monospace; }
When I test following code in chrome and nodejs, I get following:
Chrome:
for loop with VAR: 24.058ms
for loop with LET: 8.402ms
NodeJS:
for loop with VAR: 4.329ms
for loop with LET: 8.727ms
As per my understanding, because of block scoping LET is faster in chrome. But can someone help me understand why is it opposite in NodeJS?
Or am i missing something?
"use strict";
console.time("for loop with VAR");
for (var i = 0; i < 1000000; i += 1) {
// Do nothing
}
console.timeEnd("for loop with VAR");
console.time("for loop with LET");
for (let i = 0; i < 1000000; i += 1) {
// Do nothing
}
console.timeEnd("for loop with LET");`
PS: Not sure if this is not the ideal way to test performance.
V8 version shipped with node.js 5.10 don't support the temporal dead zone for let bindings.
Chrome instead is using V8 5.0 that support it...but as the vm is not yet optimized to handle TDZ, is normal that for now it's slower (I remember reading people who assert that replacing var with let made the code about 27% slower).
When you do
for (let i = 0; i < 1000000; i += 1) { }
the i value in each loop cycle is a separate reference, which is useful when using the i value in an asynchronous callback. This is slower, but can be faster than alternatives in this usage case.
When instead you use
let j;
for (j = 0; j < 1000000; ++j) { }
you will only have one value reference, and it will be just as fast as with var.
Try the following code
console.time("let i");
for (let i = 0; i < 10000000; ++i) { }
console.timeEnd("let i");
console.time("let j");
let j;
for (j = 0; j < 10000000; ++j) { }
console.timeEnd("let j");
console.time("var k");
for (var k = 0; k < 10000000; ++k) { }
console.timeEnd("var k");
this will give results like
let i: 91ms
let j: 25ms
var k: 27ms
where clearly let is equally fast to var when used correctly.
Also to see the difference in asynchronous behaviour, try
for (let i = 0; i < 3; ++i) {
setImmediate(() => { console.log(i) });
}
let j;
for (j = 0; j < 3; ++j) {
setImmediate(() => { console.log(j) });
}
for (var k = 0; k < 3; ++k) {
setImmediate(() => { console.log(k) });
}
which will output
0
1
2
3
3
3
3
3
3
as in each cycle of the loop for let i the i value is a unique reference, which is what causes the slight overhead, whereas for the other two loops it's the same reference.
i can't tell you more but as mentiont in this video (very good), you need smarter code to test this.
https://www.youtube.com/watch?v=65-RbBwZQdU
the compiler will to magic stuff with your code and might even ereas the loop if you don't use i and the loop is empty
Is it safe to assume that for time critical applications it is always better to use function declaration or function expressions, instead of inline functions in heavily executed callbacks?
Consider following test program:
var x;
var count3 = function count3() {
x++;
}
var count2 = function () {
x++;
}
function count() {
x++;
}
function execute(cb) {
cb();
}
x = 0;
var a = new Date().getTime();
for (var i = 0; i < 100000000; i++) {
execute(function named() {
x++;
})
}
a = new Date().getTime() - a;
console.log("Named inline function: " + a);
x = 0;
a = new Date().getTime();
for (var i = 0; i < 100000000; i++) {
execute(function () {
x++;
})
}
a = new Date().getTime() - a;
console.log("Anonymous inline function: " + a);
x = 0;
a = new Date().getTime();
for (var i = 0; i < 100000000; i++) {
execute(count);
}
a = new Date().getTime() - a;
console.log("Function declaration: " + a);
x = 0;
a = new Date().getTime();
for (var i = 0; i < 100000000; i++) {
execute(count2);
}
a = new Date().getTime() - a;
console.log("Anonymous function expression:" + a);
x = 0;
a = new Date().getTime();
for (var i = 0; i < 100000000; i++) {
execute(count3);
}
a = new Date().getTime() - a;
console.log("Named function expression:" + a);
This gives following output (in ms):
Named inline function: 2347
Anonymous inline function: 2121
Function declaration: 771
Anonymous function expression:750
Named function expression:752
Function declaration and function expressions are 3 times faster than inline functions on my humble laptop.
Yes, this can be generalized. Technically the function expression in the loop body is re-evaluated to a new function object every loop turn. As your tests confirm, this is noticeable slower (for millions of iterations) than having one "static" function defined outside the loop. Whether the function is named or not does not really matter, it has a very little overhead in introducing another variable in the execution contexts.
However, this is only relevant when the function really is declared inside the iteration, as in your examples. If you instead had a
function executeAll(cb) {
for (var i = 0; i < 100000000; i++) {
cb();
}
}
then there be no difference between
executeAll(function() { x++; });
and
function increase() { x++; }
executeAll(increase);
since the cb argument is the "static" reference to the one function.