什么算作IE的“停止运行此脚本?”的“执行脚本声明”?警告柜台?

时间:2014-02-12 10:33:42

标签: javascript internet-explorer

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之前完成,则可以在没有对话框的情况下执行超过默认限制。

给出一些看似含糊不清的简单例子:

  1. var a = 1, b = 2, c = 3;计为一个“已执行的脚本声明”,var a = 1; var b = 2; var c = 3;计为三个?或者两者都是三个?
  2. if( someFunction() ){} {不计算someFunction()内的陈述是一个陈述,还是两个(来电加条件)?
  3. if(a){}else{}是一个或两个条件语句?如果是,if(a){}else if(b){}会是两个吗?
  4. if(a==b||(c&&a==c&&c==d)){}是一,二,三,四,五个陈述(或更多?)?我知道像if(a){}之类的东西调用Javascript函数转换为boolean - 这会在比较本身之上添加额外的语句吗?
  5. 因为它添加了一个赋值,var value = someFunction(); if( value ){}会是三个,还是将函数调用计算为赋值语句的一部分?
  6. 链接怎么样?例如,如果使用jQuery,那么(不计算每个函数中执行的脚本语句)是行$(selector).show().css(obj).appendTo($el);一个“执行脚本语句”,还是四个?我想这将是四个“电话”声明。
  7. 据推测,var $someEl = $(selector).show().css(obj).appendTo($el);会将此增加到五个语句 - 四个调用加一个赋值? (IE不会把它算作一个赋值语句并继续前进吗?)
  8. 当然,上面这些简单的例子都是小型的 - 我试图“了解敌人”,以便能够判断如何最好地优化复杂的循环。

    我正在寻找经验法则或一些如上所述的例子

2 个答案:

答案 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论文中所述。

您可以修改代码以自行查看哪种指令被计为语句。

到目前为止我的经验观察:

似乎一个陈述确实接近语法定义,即直到下一个;才发现的任何内容。

  • 循环计为2个语句(可能是测试和indice更新)
  • 函数调用计为2个语句,无论结果如何影响变量
  • 任意复杂的表达式评估计为单个陈述
  • 内置函数不计为语句,但在用户定义的语句中执行的每个语句都可以。

通过将计算打包成更复杂的单个语句,您似乎可以在5M允许的语句中填充更多权力。

所有这些都说,如果你问我,使用浏览器执行重型计算的设计根本就存在缺陷。

答案 1 :(得分:0)

据我所知,浏览器从队列中执行代码。

当某些代码正在运行并且您创建了一个setTimeout()时,即使您将超时设置为4毫秒(每个浏览器可能不同,下面没有注释),该代码也不会与其他JavaScript代码并行执行浏览器。而是将该函数放入队列中。

当前正在执行的脚本完成后,它将在队列中查找要执行的下一个项目。队列可以有事件处理程序(来自用户输入,虽然我认为它们可能被优先化,不确定)和Ajax调用响应(如jQuery ajax调用成功代码等),它们都被添加到队列中并且它们被执行一个一次。

JavaScript总是在一个线程中运行,从来没有两个线程并行运行JavaScript代码。那个线程从队列中挑出东西并一次执行一个。

注意:最好不要在big for循环中运行,因为这会触发你得到的错误。