【问题标题】:Disabling the long-running-script message in Internet Explorer在 Internet Explorer 中禁用长时间运行的脚本消息
【发布时间】:2010-12-16 11:26:14
【问题描述】:

我有一个 JavaScript 函数,其中包含一个迭代了很多次的 for 循环。
调用该函数后,IE浏览器显示如下信息:

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

我该如何解决这个问题?
无论如何我可以从 IE 中禁用此消息吗?

【问题讨论】:

  • 首先,请向我们展示您的代码。其次,在 IE 中禁用此消息的方法是修复您的代码。
  • - 哪个版本的 IE ?如果不是代码问题,不妨试试superuser.com
  • @Eric Leschinski 回答对我有用...
  • 您可以使用注册表来执行此操作。见here

标签: javascript internet-explorer


【解决方案1】:

当 Internet Explorer 达到一段 JavaScript 的最大同步指令数时,将显示此消息。默认最大值为 5,000,000 条指令,您可以在单机上将此数量增加editing the registry

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;
        }
    }
})();

【讨论】:

  • 非常感谢您链接到注册表黑客。我一直在尝试在 VM 上运行几个性能测试,而 IE 弹出对话框破坏了结果。我花了很长时间才找到这个问题,但希望通过添加此评论并提及几个关键字(例如“停止运行此脚本?”和“IE 弹出对话框”),它会在 google 中显示得更高。跨度>
  • 如果你不给 setTimeout 一个明确的时间,即。跳过第二个参数,这个脚本会运行得更快,你会得到同样的效果。不提供第二个参数会告诉浏览器“尽快”而不是“至少在这么长时间之后”触发传递的函数。
  • @AndyE - 我通常不包含参数,但我看到 jQuery 出于某种我不理解的原因在使用 0 和 1ms 延迟之间切换(可能与某些东西向后兼容),但它是从来没有省略,所以我在提供建议时会模仿。我确实知道几年前 jQuery 对动画帧有一个 13 毫秒的硬编码超时,这有点难以解决。也许这个下限是你在想的?或者也许计算机在过去更慢。
  • @AndyE - 我在圣诞节假期做了更多的实验,并就这个主题写了一些文章,比直接发布到 Stack Overflow 更深入一些。想你可能会感兴趣,thedavidmeister.info/post/…
  • @DavidMeister,该链接已失效
【解决方案2】:

当某些 javascript 线程耗时太长太完整时,会显示无响应的脚本对话框。编辑注册表可以工作,但您必须在所有客户端计算机上进行。您可以按如下方式使用“递归闭包”来缓解问题。它只是一种编码结构,它允许您长时间运行 for 循环并将其更改为可以完成某些工作的东西,并跟踪它停止的地方,让给浏览器,然后继续它停止的地方,直到我们完成。

图 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();
  };
};

图 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.
  }
}

图 3。以下代码是图 2 中问题代码的修复。请注意,for 循环已替换为递归闭包,该闭包每 10 次重载任务()迭代将控制权传递回浏览器

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.

};

改编自以下来源:

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 秒的时间段,由于硬编码的最小延迟设置超时()。请参阅关于 Andy E 答案的评论主题。
【解决方案3】:

就我而言,在播放视频时,我需要在每次 currentTime 视频更新时调用一个函数。所以我使用了timeupdate 视频事件,我知道它每秒至少触发 4 次(取决于您使用的浏览器,请参阅this)。所以我把它改成这样每秒调用一个函数:

var currentIntTime = 0;

var someFunction = function() {
    currentIntTime++;
    // Do something here
} 
vidEl.on('timeupdate', function(){
    if(parseInt(vidEl.currentTime) > currentIntTime) {
        someFunction();
    }
});

这减少了对someFunc 的调用至少1/3,它可以帮助您的浏览器正常运行。对我有用!!!

【讨论】:

    【解决方案4】:

    我无法评论以前的答案,因为我没有尝试过。但是我知道以下策略对我有用。它有点不那么优雅,但可以完成工作。它也不需要像其他一些方法那样将代码分成块。就我而言,这不是一个选择,因为我的代码对正在循环的逻辑进行了递归调用;也就是说,没有实际的方法可以跳出循环,然后能够通过使用全局变量以某种方式恢复以保留当前状态,因为这些全局变量可以通过在随后的递归调用中引用它们来更改。所以我需要一种直接的方式,不会让代码有机会破坏数据状态的完整性。

    假设“停止脚本”?在经过多次迭代(在我的情况下,大约 8-10 次)之后,在 for() 循环执行期间出现对话框,并且无法选择弄乱注册表,这是修复方法(无论如何对我来说):

    var anarray = [];
    var array_member = null;
    var counter = 0; // Could also be initialized to the max desired value you want, if
                     // planning on counting downward.
    
    function func_a()
    {
     // some code
     // optionally, set 'counter' to some desired value.
     ...
     anarray = { populate array with objects to be processed that would have been
                 processed by a for() }
     // 'anarry' is going to be reduced in size iteratively.  Therefore, if you need
     //  to maintain an orig. copy of it, create one, something like 'anarraycopy'.
     //  If you need only a shallow copy, use 'anarraycopy = anarray.slice(0);'
     //  A deep copy, depending on what kind of objects you have in the array, may be
     //  necessary.  The strategy for a deep copy will vary and is not discussed here.
     //  If you need merely to record the array's orig. size, set a local or
     //  global var equal to 'anarray.length;', depending on your needs.
     // - or -
     // plan to use 'counter' as if it was 'i' in a for(), as in
     // for(i=0; i < x; i++ {...}
    
       ...
    
       // Using 50 for example only.  Could be 100, etc. Good practice is to pick something
       // other than 0 due to Javascript engine processing; a 0 value is all but useless
       // since it takes time for Javascript to do anything. 50 seems to be good value to
       // use. It could be though that what value to use does  depend on how much time it
       // takes the code in func_c() to execute, so some profiling and knowing what the 
       // most likely deployed user base is going to be using might help. At the same 
       // time, this may make no difference.  Not entirely sure myself.  Also, 
       // using "'func_b()'" instead of just "func_b()" is critical.  I've found that the
       // callback will not occur unless you have the function in single-quotes.
    
       setTimeout('func_b()', 50);
    
      //  No more code after this.  function func_a() is now done.  It's important not to
      //  put any more code in after this point since setTimeout() does not act like
      //  Thread.sleep() in Java.  Processing just continues, and that is the problem
      //  you're trying to get around.
    
    } // func_a()
    
    
    function func_b()
    {
     if( anarray.length == 0 )
     {
       // possibly do something here, relevant to your purposes
       return;
     }
    //  -or- 
    if( counter == x ) // 'x' is some value you want to go to.  It'll likely either
                       // be 0 (when counting down) or the max desired value you
                       // have for x if counting upward.
    {
      // possibly do something here, relevant to your purposes
      return;
    }
    
    array_member = anarray[0];
    anarray.splice(0,1); // Reduces 'anarray' by one member, the one at anarray[0].
                         // The one that was at anarray[1] is now at
                         // anarray[0] so will be used at the next iteration of func_b().
    
    func_c();
    
    setTimeout('func_b()', 50);
    
    } // func_b()
    
    
    function func_c()
    {
      counter++; // If not using 'anarray'.  Possibly you would use
                 // 'counter--' if you set 'counter' to the highest value
                 // desired and are working your way backwards.
    
      // Here is where you have the code that would have been executed
      // in the for() loop.  Breaking out of it or doing a 'continue'
      // equivalent can be done with using 'return;' or canceling 
      // processing entirely can be done by setting a global var
      // to indicate the process is cancelled, then doing a 'return;', as in
      // 'bCancelOut = true; return;'.  Then in func_b() you would be evaluating
      // bCancelOut at the top to see if it was true.  If so, you'd just exit from
      // func_b() with a 'return;'
    
    } // func_c()
    

    【讨论】:

      猜你喜欢
      • 2020-04-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-02
      • 1970-01-01
      • 2019-02-12
      • 2013-01-16
      相关资源
      最近更新 更多