Internet Explorer 8(我需要支持,不可协商)显示the following warning once 5,000,000 "executed script statements" have occurred in one synchronous script execution(例如,来自超时或来自事件处理程序)。
停止运行此脚本?此页面上的脚本正在导致您的网络 浏览器运行缓慢。如果它继续运行,您的计算机可能会 变得反应迟钝。
我正在尝试优化一些复杂的重载代码以避免此错误消息。我已经遵循了标准建议,即尽可能使用setTimeout()
之类的东西将代码分解为单独的异步块。在没有创建竞争条件的情况下,我无法做更多这样的事情,因此我希望简化多次发生的所有代码,例如:在大for
循环中。
要做到这一点,我想了解IE究竟是什么算作“已执行的脚本声明”,所以我会知道我的循环中哪些优化会产生最大的差异,哪些优化不会。
我查找了“已执行脚本语句”的标准定义,但没有成功 - 大多数时候使用“脚本语句”,它似乎是指html <script>
标记的内容,这显然是一个不同的这个词的意义。定义Statement (computer science)很有帮助,但是对它们的计算方式有些模棱两可(见下面的例子)。
Here's what Microsoft have to say on the matter(为了便于阅读,我添加了分段符号):
从Internet Explorer 4.0及更高版本开始,超时不再是基于Windows消息的固定值。 Internet Explorer现在跟踪已执行的脚本语句的总数,并在每次启动新脚本时重置该值,例如从超时或事件处理程序,对于具有脚本引擎的当前页面。
当该值超过阈值量时,Internet Explorer会显示“长时间运行的脚本”对话框。
Internet Explorer不检查每条指令是否超出限制。脚本引擎定期轮询Internet Explorer,执行的语句数量和Internet Explorer检查是否超出限制。由于这种机制,如果整个脚本执行在脚本引擎轮询Internet Explorer之前完成,则可以在没有对话框的情况下执行超过默认限制。
给出一些看似含糊不清的简单例子:
var a = 1, b = 2, c = 3;
计为一个“已执行的脚本声明”,var a = 1; var b = 2; var c = 3;
计为三个?或者两者都是三个?if( someFunction() ){}
{不计算someFunction()
内的陈述是一个陈述,还是两个(来电加条件)?if(a){}else{}
是一个或两个条件语句?如果是,if(a){}else if(b){}
会是两个吗?if(a==b||(c&&a==c&&c==d)){}
是一,二,三,四,五个陈述(或更多?)?我知道像if(a){}
之类的东西调用Javascript函数转换为boolean - 这会在比较本身之上添加额外的语句吗?var value = someFunction(); if( value ){}
会是三个,还是将函数调用计算为赋值语句的一部分?$(selector).show().css(obj).appendTo($el);
一个“执行脚本语句”,还是四个?我想这将是四个“电话”声明。$someEl = $(selector).show().css(obj).appendTo($el);
会将此增加到五个语句 - 四个调用加一个赋值? (IE不会把它算作一个赋值语句并继续前进吗?)当然,上面这些简单的例子都是小型的 - 我试图“了解敌人”,以便能够判断如何最好地优化复杂的循环。
我正在寻找经验法则或一些如上所述的例子
答案 0 :(得分:2)
除非有一些Microsoft IE8开发人员来回答你的问题,否则只能猜到你所要求的内容 作为一个与微软毫无关系的青蛙,我设计了一个简单的测试,试图测量语句的计数方式:
<body>
<div id='div'></div>
<script>
var count = 5000000;
var res = 0;
var d = document.getElementById ('div');
function fun (aaa) // 1 statement
{
aaa+= Math.random(); // 1 statement
aaa+= Math.random(); // 1 statement
aaa+= Math.random(); // 1 statement
}
function format (count) // 1 statement
{
return Math.round(count*100/i)/100; // 1 statement
}
function format2 (count) // 1 statement
{
var a = count*100; //4 statements
var b = a / i;
var c = Math.round (b);
var d = c/100;
return d; // 1 statement
}
for (var i = 0 ; i != count ; i++) // 2 statements
{
res += Math.random(); // 1 statement
d.innerHTML = format2(count); // 1 statement
d.innerHTML = Math.round(count*100/i)/100; // 1 statement
fun (res); // 1 statement
}
</script>
</body>
我在VirtualBox上通过XP在IE8上运行了这个脚本。
页面中显示的数字大致表示每个循环的语句数(因为IE计算它们)。不精确可能是由于语句计数的异步轮询,如Microsoft论文中所述。
您可以修改代码以自行查看哪种指令被计为语句。
到目前为止我的经验观察:
似乎一个陈述确实接近语法定义,即直到下一个;
才发现的任何内容。
通过将计算打包成更复杂的单个语句,您似乎可以在5M允许的语句中填充更多权力。
所有这些都说,如果你问我,使用浏览器执行重型计算的设计根本就存在缺陷。
答案 1 :(得分:0)
据我所知,浏览器从队列中执行代码。
当某些代码正在运行并且您创建了一个setTimeout()时,即使您将超时设置为4毫秒(每个浏览器可能不同,下面没有注释),该代码也不会与其他JavaScript代码并行执行浏览器。而是将该函数放入队列中。
当前正在执行的脚本完成后,它将在队列中查找要执行的下一个项目。队列可以有事件处理程序(来自用户输入,虽然我认为它们可能被优先化,不确定)和Ajax调用响应(如jQuery ajax调用成功代码等),它们都被添加到队列中并且它们被执行一个一次。
JavaScript总是在一个线程中运行,从来没有两个线程并行运行JavaScript代码。那个线程从队列中挑出东西并一次执行一个。
注意:最好不要在big for循环中运行,因为这会触发你得到的错误。