在Internet Explorer中禁用长时间运行脚本消息

sca*_*man 49 javascript internet-explorer

我有一个JavaScript函数,其中包含一个迭代很多次的for循环.
调用此函数后,IE浏览器显示以下消息:

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

我怎样才能解决这个问题?
无论如何我可以从IE禁用此消息?

And*_*y E 80

当Internet Explorer达到一段JavaScript的最大同步指令数时,将显示此消息.默认最大值为5,000,000条指令,您可以通过编辑注册表在单台计算机上增加此数字.

Internet Explorer现在跟踪已执行的脚本语句的总数,并在每次启动新脚本时重置该值,例如从超时或事件处理程序,对于具有脚本引擎的当前页面.当该值超过阈值量时,Internet Explorer将显示"长时间运行的脚本"对话框.

解决可能正在查看页面的所有用户的问题的唯一方法是使用计时器分解循环执行的迭代次数,或者重构代码以使其不需要处理尽可能多的指令.

使用计时器打破循环相对简单:

var i=0;
(function () {
    for (; i < 6000000; i++) {
        /*
            Normal processing here
        */

        // Every 100,000 iterations, take a break
        if ( i > 0 && i % 100000 == 0) {
            // Manually increment `i` because we break
            i++;
            // Set a timer for the next iteration 
            window.setTimeout(arguments.callee);
            break;
        }
    }
})();
Run Code Online (Sandbox Code Playgroud)

  • 非常感谢你链接到注册表黑客.我一直在尝试在VM上运行几个性能测试,并且IE弹出对话框破坏了结果.我有一段时间找到这个问题,但希望通过添加此评论并提及几个关键字(如"停止运行此脚本?"和"IE弹出对话框"),它将在谷歌中显示更高. (4认同)
  • @AndyE - 我在圣诞假期做了一些实验,并对这个主题进行了一些写作,比直接发布到Stack Overflow更深入一些.您可能对此感兴趣,http://thedavidmeister.info/post/techniques-help-manage-long-running-scripts-and-avoid-timeout-errors (3认同)
  • 如果你没有给setTimeout一个明确的时间,即.跳过第二个参数,这个脚本将运行得更快,你将获得相同的效果.不提供第二个参数告诉浏览器"尽快"触发传递的函数,而不是"至少在这么多时间之后". (2认同)
  • @AndyE - 我通常不包括参数,但我看到jQuery在使用0和1ms延迟之间交换,由于某些我不理解的原因(可能向后兼容某些东西)但它永远不会被忽略所以我模仿当我提供建议.我知道几年前jQuery对于动画帧有一个13ms的硬编码超时,这对于解决这个问题来说有点痛苦.也许这个下限是你想到的?或者计算机过去只是速度较慢. (2认同)
  • @DavidMeister,该链接已失效 (2认同)

Eri*_*ski 12

无响应的脚本对话框显示某些javascript线程太长时间太完整.编辑注册表可以工作,但您必须在所有客户端计算机上执行此操作.你可以使用如下的"递归闭包"来缓解这个问题.它只是一个编码结构,允许你长时间运行循环并将其转换为可以完成某些工作的东西,并跟踪它停止的位置,屈服于浏览器,然后继续它停止的地方直到我们完成.

图1,将此实用程序类RepeatingOperation添加到您的javascript文件中.您无需更改此代码:

RepeatingOperation = function(op, yieldEveryIteration) {

  //keeps count of how many times we have run heavytask() 
  //before we need to temporally check back with the browser.
  var count = 0;   

  this.step = function() {

    //Each time we run heavytask(), increment the count. When count
    //is bigger than the yieldEveryIteration limit, pass control back 
    //to browser and instruct the browser to immediately call op() so
    //we can pick up where we left off.  Repeat until we are done.
    if (++count >= yieldEveryIteration) {
      count = 0;

      //pass control back to the browser, and in 1 millisecond, 
      //have the browser call the op() function.  
      setTimeout(function() { op(); }, 1, [])

      //The following return statement halts this thread, it gives 
      //the browser a sigh of relief, your long-running javascript
      //loop has ended (even though technically we havn't yet).
      //The browser decides there is no need to alarm the user of
      //an unresponsive javascript process.
      return;
      }
    op();
  };
};
Run Code Online (Sandbox Code Playgroud)

图2,以下代码表示导致"停止运行此脚本"对话框的代码,因为它需要很长时间才能完成:

process10000HeavyTasks = function() {
  var len = 10000;  
  for (var i = len - 1; i >= 0; i--) {
    heavytask();   //heavytask() can be run about 20  times before
                   //an 'unresponsive script' dialog appears.
                   //If heavytask() is run more than 20 times in one
                   //javascript thread, the browser informs the user that
                   //an unresponsive script needs to be dealt with.  

                   //This is where we need to terminate this long running
                   //thread, instruct the browser not to panic on an unresponsive
                   //script, and tell it to call us right back to pick up
                   //where we left off.
  }
}
Run Code Online (Sandbox Code Playgroud)

图3.以下代码是图2中有问题代码的修复.请注意,for循环被替换为递归闭包,每10次repeattask()迭代将控制权传递回浏览器

process10000HeavyTasks = function() {

  var global_i = 10000; //initialize your 'for loop stepper' (i) here.

  var repeater = new this.RepeatingOperation(function() {

    heavytask();

    if (--global_i >= 0){     //Your for loop conditional goes here.
      repeater.step();        //while we still have items to process,
                              //run the next iteration of the loop.
    }
    else {
       alert("we are done");  //when this line runs, the for loop is complete.
    }
  }, 10);                   //10 means process 10 heavytask(), then
                            //yield back to the browser, and have the
                            //browser call us right back.

  repeater.step();          //this command kicks off the recursive closure.

};
Run Code Online (Sandbox Code Playgroud)

改编自此来源:

http://www.picnet.com.au/blogs/Guido/post/2010/03/04/How-to-prevent-Stop-running-this-script-message-in-browsers

  • 我认为你不想这样做,因为RepeatingOperation只能被调用1000次并导致至少4-10秒的时间段,由于setTimeout()上的硬编码延迟,网站没有响应.请参阅Andy E答案的评论主题. (4认同)