为什么在“for”循环中使用`let`在Chrome上这么慢? [英] Why is using `let` inside a `for` loop so slow on Chrome?

查看:156
本文介绍了为什么在“for”循环中使用`let`在Chrome上这么慢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

MAJOR UPDATE。



目前还没有在Chrome主要版本上发布新的
Chrome版本55.0。 2883.35 beta,Windows 10。



一张价值千言万语的图片,应该是第一个看的地方。



上述配置文件的相关功能

  var time = [ 0,0]; // hold total times 

function letInside(){
var start = performance.now(); (let i = 0; i< 1e5; i + = 1)的

; //< - 如果你在家尝试这个,别忘了;

time [0] + = performance.now() - start;
setTimeout(letOutside,10);
}

函数letOutside(){//这个函数是chrome的两倍快
var start = performance.now();

{let i; for(i = 0; i <1e5; i + = 1)}

time [1] + = performance.now() - start;
setTimeout(displayResults,10);
}

由于Chrome是主要播放器,循环计数器的阻止范围变量无处不在那些需要执行代码并且感觉到块范围变量的人很重要 function {}(for(let i; i< 2; i ++} {...})//?WHY?应该考虑暂时的替代语法,并在循环之外声明循环计数器。



我想说,时差是微不足道的,但是事实上,使用 for(let i ... )来优化函数内的所有代码都应该小心使用。





MAJOR UPDATE.

Thought as yet not on the Chrome major release the new Ignition+Turbofan engines for Chrome Canary 59 has solved the problem. Test show identical times for let and var declared loop variables.


Original (now mute) question.

When using let in a for loop on Chrome it runs very slowly, compared to moving the variable just outside the loop's scope.

for(let i = 0; i < 1e6; i ++); 

takes twice as long as

{ let i; for(i = 0; i < 1e6; i ++);}

What is going on?

Snippet demonstrates the difference and only affects Chrome and has been so for as long as I can remember Chrome supporting let.

var times = [0,0]; // hold total times
var count = 0;  // number of tests

function test(){
    var start = performance.now();
    for(let i = 0; i < 1e6; i += 1){};
    times[0] += performance.now()-start;
    setTimeout(test1,10)
}
function test1(){
    // this function is twice as quick as test on chrome
    var start = performance.now();
    {let i ; for(i = 0; i < 1e6; i += 1);}
    times[1] += performance.now()-start;
    setTimeout(test2,10)
}

// display results
function test2(){
    var tot =times[0]+times[1];
    time.textContent = tot.toFixed(3)  + "ms";
    time1.textContent = ((times[0]/tot)*100).toFixed(2) + "% " + times[0].toFixed(3)  + "ms";
    time2.textContent = ((times[1]/tot)*100).toFixed(2) + "% " + times[1].toFixed(3) + "ms";
    if(count++ < 1000){;
        setTimeout(test,10);
    }
}
var div = document.createElement("div");
var div1 = document.createElement("div");
var div2 = document.createElement("div");
var time = document.createElement("span");
var time1 = document.createElement("span");
var time2 = document.createElement("span");
div.textContent = "Total execution time : "
div1.textContent = "Test 1 : "
div2.textContent = "Test 2 : "
div.appendChild(time);
div1.appendChild(time1);
div2.appendChild(time2);
document.body.appendChild(div);
document.body.appendChild(div1);
document.body.appendChild(div2);
test2()

When I first encountered this I thought it was because of the newly created instance of i but the following shows this is not so.

See code snippet as I have eliminated any possibility of the additional let declaration being optimised out with ini with random and then adding to indeterminate value of k.

I also added a second loop counter p

var times = [0,0]; // hold total times
var count = 0;  // number of tests
var soak = 0; // to stop optimizations
function test(){
    var j;
    var k = time[1];
    var start = performance.now();
    for(let p =0, i = 0; i+p < 1e3; p++,i ++){j=Math.random(); j += i; k += j;};
    times[0] += performance.now()-start;
    soak += k;
    setTimeout(test1,10)
}
function test1(){
    // this function is twice as quick as test on chrome
    var k = time[1];
    var start = performance.now();
    {let p,i ; for(p = 0,i = 0; i+p < 1e3; p++, i ++){let j = Math.random(); j += i; k += j}}
    times[1] += performance.now()-start;
    soak += k;
    setTimeout(test2,10)
}

// display results
function test2(){
    var tot =times[0]+times[1];
    time.textContent = tot.toFixed(3)  + "ms";
    time1.textContent = ((times[0]/tot)*100).toFixed(2) + "% " + times[0].toFixed(3)  + "ms";
    time2.textContent = ((times[1]/tot)*100).toFixed(2) + "% " + times[1].toFixed(3) + "ms";
    if(count++ < 1000){;
        setTimeout(test,10);
    }
}
var div = document.createElement("div");
var div1 = document.createElement("div");
var div2 = document.createElement("div");
var time = document.createElement("span");
var time1 = document.createElement("span");
var time2 = document.createElement("span");
div.textContent = "Total execution time : "
div1.textContent = "Test 1 : "
div2.textContent = "Test 2 : "
div.appendChild(time);
div1.appendChild(time1);
div2.appendChild(time2);
document.body.appendChild(div);
document.body.appendChild(div1);
document.body.appendChild(div2);
test2()

解决方案

MAJOR UPDATE.

Thought as yet not on the Chrome major release the new Ignition+Turbofan engines for Chrome Canary 60.0.3087 has solved the problem. Test show identical times for let and var declared loop variables.

Side note. My testing code uses Function.toString() and failed on Canary because it returns "function() {" not "function () {" as past versions (easy fix using regexp) but a potencial problem for those that use Function.toSting()

Update Thanks to the user Dan. M who provide the link https://bugs.chromium.org/p/v8/issues/detail?id=4762 (and heads up) which has more on the issue.


Previous answer

Optimiser opted out.

This question has puzzled me for some time and the two answers are the obvious answers, but it made no sense as the time difference was too great to be the creation of a new scoped variable and execution context.

In an effort to prove this I found the answer.

Short answer

A for loop with a let statement in the declaration is not supported by the optimiser.

Chrome Version 55.0.2883.35 beta, Windows 10.

A picture worth a thousand words, and should have been the first place to look.

The relevant functions for the above profile

var time = [0,0]; // hold total times

function letInside(){
    var start = performance.now();

    for(let i = 0; i < 1e5; i += 1); // <- if you try this at home don't forget the ;

    time[0] += performance.now()-start;
    setTimeout(letOutside,10);
}

function letOutside(){ // this function is twice as quick as test on chrome
    var start = performance.now();

    {let i; for(i = 0; i < 1e5; i += 1)}

    time[1] += performance.now()-start;
    setTimeout(displayResults,10);
}

As Chrome is the major player and the blocked scoped variables for loop counters are everywhere, those who need performant code and feel that block scoped variables are important function{}(for(let i; i<2;i++}{...})//?WHY?should consider for the time being the alternative syntax and declare the loop counter outside the loop.

I would like to say that the time difference is trivial, but in light of the fact that all code within the function is not optimized using for(let i... should be used with care.


这篇关于为什么在“for”循环中使用`let`在Chrome上这么慢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆