2014-02-12 44 views
5

Internet Explorer 8(我需要支持,不幸的是,不可协商)显示the following warning once 5,000,000 "executed script statements" have occurred in one synchronous script execution(例如,来自超时或来自事件处理程序)。对于IE的“停止运行此脚本?”,什么是“执行脚本语句”?警告柜台?

停止运行此脚本?此页上的脚本导致您的网络浏览器运行缓慢。如果它继续运行,您的计算机可能会变得无响应。

我想优化一些复杂的重型代码,以避免此错误消息。我已经遵循标准的建议,这是尽可能的使用诸如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之前完成整个脚本的执行,则可以在没有对话框的情况下执行超过默认限制。

举,似乎模棱两可给我一些简单的例子:

  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函数来转换为布尔值 - 这是否会在比较本身上添加其他语句?
  5. var value = someFunction(); if(value){}三个,因为它增加了一个赋值,或者将函数调用作为赋值语句的一部分吗?
  6. 链接怎么样?例如,如果使用jQuery,那么(不包括执行的脚本语句内的每个函数)是行$(selector).show().css(obj).appendTo($el);一个“已执行的脚本语句”,还是四个?我想可能会是四个“呼叫”声明。
  7. 据推测,var $someEl = $(selector).show().css(obj).appendTo($el);会将此增加到五个语句 - 四个呼叫加分配? (IE将不只是指望它作为一个赋值语句被感动吗?)

当然以上这些简单的例子是小混混 - 我试图“了解敌人”这里可以判断如何最好优化复杂的循环。

我正在寻找无论是经验法则或一些解释例子像上面

+0

我不能说明确的,但'var whatever'几乎肯定不会计数,因为该语句不在运行时运行。除此之外,它的_probably_一行代码执行,如果if(foo){'或您的长jQuery链在最后。然而,jQuery链可能会在jQuery库中运行几百行代码。换句话说,#1是0,#5是2(用分号隔开),其他所有的都是1.但是你必须遵循代码路径来查看在#2,#5中实际运行了多少代码, #6,#7 –

回答

0

据我了解浏览器中执行代码掀起了队列。

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

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

JavaScript总是在单线程中运行,并没有两个线程并行运行JavaScript代码。一个线程从队列中选取一些内容并一次执行一个内容。

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

+0

setTimeout of 0 has mixed results。它曾经在一些浏览器中立即运行,但我不记得我的头顶哪个。因此,1的超时更安全(在大多数浏览器中的行为完全相同) –

+0

@zyklus我认为所有浏览器现在默认setTimeout(func,0)设置为setTimeout(func,4)甚至更大(即,有他们会支持的最小下限),但你可能是对的,我可以明白为什么这样做是明智的(特别是我们实际上并不知道每个浏览器如何处理这个问题)。 – jwwishart

+0

大多数浏览器都这么做,但正如我所说的,一些浏览器用'func()'读'setTimeout(func,0)'。而且他们并没有完全“将其改变”为“4ms”,“10ms”,无论定时器如何,这就是那些浏览器的冲刷周期。如果你有一个10ms刷新的浏览器,并在周期开始时运行1ms的setTimeout,它将在10ms后运行。但是,如果您先咀嚼9ms的CPU时间,则会在1ms后运行。 –

2

你所要求的只能被猜测,除非一些微软的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> 

我在XP在VirtualBox的运行在IE8这个脚本。

页面中显示的数字大致表示每个循环的语句数(按IE计数)。不精确性可能是由于对语句计数的异步轮询所致,正如微软论文中所解释的那样。

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

我的经验观察至今:

这似乎是一个声明的确是接近语法定义,即发现,直到下一个;什么。

  • 环算作2个语句(测试和指数之更新,可能)
  • 函数调用计数为2条语句,而不管结果受到影响到可变
  • 任意复杂的表达式求值作为单个语句计数
  • 内建函数不计算为语句,但每个语句都在用户定义的语句中执行。

看来你可以通过将计算包装到更复杂的单个语句中来在5M允许的语句内塞入更多的功率。如果你问我,那么使用浏览器执行重型计算的设计是根本上有缺陷的。