Отключение сообщения продолжительного скрипта в Internet Explorer - PullRequest
49 голосов
/ 16 декабря 2010

У меня есть функция JavaScript, которая содержит цикл for, который повторяется так много раз.
После вызова этой функции браузер IE отображает следующее сообщение:

Прекратить запуск этого сценария?
Сценарий на этой странице вызывает медленную работу вашего веб-браузера.Если он продолжает работать, ваш компьютер может перестать отвечать на запросы.

Как я могу это исправить?
Есть ли возможность отключить это сообщение от IE?

Ответы [ 4 ]

80 голосов
/ 16 декабря 2010

Это сообщение отображается, когда 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;
        }
    }
})();
12 голосов
/ 23 июля 2012

Диалоговое окно не отвечающего скрипта показывает, когда какой-то поток 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

1 голос
/ 13 июля 2015

В моем случае во время воспроизведения видео мне нужно было вызывать функцию 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 и может помочь вашему браузеру вести себя нормально.Это сделал для меня !!!

0 голосов
/ 26 июня 2013

Я не могу комментировать предыдущие ответы, так как я не пробовал их.Однако я знаю, что следующая стратегия работает для меня.Это немного менее элегантно, но выполняет свою работу.Также не требуется разбивать код на куски, как это делают некоторые другие подходы.В моем случае это не выход, потому что в моем коде были рекурсивные вызовы зацикливающейся логики;то есть, не было никакого практического способа просто выйти из цикла, а затем иметь возможность каким-либо образом возобновить работу, используя глобальные переменные для сохранения текущего состояния, поскольку эти глобальные переменные могли быть изменены ссылками на них в последующем повторяющемся вызове.Поэтому мне нужен был простой способ, который не давал бы шансу кода нарушить целостность состояния данных.

Предполагается, что «сценарий остановки?»диалоговое окно появляется во время выполнения цикла for () после нескольких итераций (в моем случае, около 8-10), и связывание с реестром не вариант, здесь было исправление (для меня, во всяком случае):

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()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...