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

时间:2010-12-16 11:26:15

标签: javascript internet-explorer

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

  

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

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

4 个答案:

答案 0 :(得分:80)

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

答案 1 :(得分: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();
  };
};

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

};

改编自此来源:

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

答案 2 :(得分:1)

就我而言,在播放视频时,我需要每次<div id="header"> <a href="index.php"> <img id="logo" src="./images/logo.png" /> </a> <div id="navigation"> <ul> <a href="./index.php"> <li>Home</li> </a> <a href="./newsletter.php"> <li>Newsletter</li> </a> <a href="../users/list.php"> <li>User List</li> </a> <a href="./admin/index.php"> <li>Admin Panel</li> </a> </ul> </div> </div> <div id="content"> <p> <br /> <h2></h2> <br /> <br /> <ol> </ol> </p> </div> <div id="footer"> <p class="copyright"></p> </div>视频更新时调用一个函数。所以我使用了currentTime视频事件,我发现它每秒至少被触发4次(取决于您使用的浏览器,请参阅this)。所以我把它改成每隔一秒调用一个函数:

timeupdate

这会将var currentIntTime = 0; var someFunction = function() { currentIntTime++; // Do something here } vidEl.on('timeupdate', function(){ if(parseInt(vidEl.currentTime) > currentIntTime) { someFunction(); } }); 的通话时间减少至少someFunc,这可能有助于您的浏览器正常运行。它对我有用!!!

答案 3 :(得分:0)

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

假设“停止脚本?”在多次迭代(在我的情况下,大约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()