Javascript 在 Internet Explorer 中禁用长时间运行的脚本消息
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4460263/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Disabling the long-running-script message in Internet Explorer
提问by scatman
I have a JavaScript function that contains a for loop that iterates so many times.
After calling this function, the IE browser displays this message:
我有一个 JavaScript 函数,它包含一个迭代了很多次的 for 循环。
调用该函数后,IE浏览器显示如下信息:
Stop running this script?
A script on this page is causing your web browser to run slowly. If it continues to run, your computer might become unresponsive.
停止运行此脚本?
此页面上的脚本导致您的 Web 浏览器运行缓慢。如果它继续运行,您的计算机可能会变得无响应。
How can I fix this?
is there anyway I can disable this message from IE?
我怎样才能解决这个问题?
无论如何我可以从 IE 中禁用此消息吗?
回答by Andy E
This message displays when Internet Explorer reaches the maximum number of synchronous instructions for a piece of JavaScript. The default maximum is 5,000,000 instructions, you can increase this number on a single machine by editing the registry.
当 Internet Explorer 达到一段 JavaScript 的最大同步指令数时,将显示此消息。默认最大值为 5,000,000 条指令,您可以通过编辑注册表在单台机器上增加此数量。
Internet Explorer now tracks the total number of executed script statements and resets the value each time that a new script execution is started, such as from a timeout or from an event handler, for the current page with the script engine. Internet Explorer displays a "long-running script" dialog box when that value is over a threshold amount.
Internet Explorer 现在会跟踪已执行脚本语句的总数,并在每次启动新脚本执行时重置该值,例如从超时或事件处理程序开始,用于使用脚本引擎的当前页面。当该值超过阈值时,Internet Explorer 会显示一个“长时间运行的脚本”对话框。
The only way to solve the problem for all users that might be viewing your page is to break up the number of iterations your loop performs using timers, or refactor your code so that it doesn't need to process as many instructions.
为可能正在查看您的页面的所有用户解决问题的唯一方法是使用计时器分解循环执行的迭代次数,或者重构您的代码以便它不需要处理尽可能多的指令。
Breaking up a loop with timers is relatively straightforward:
用定时器打破循环相对简单:
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;
}
}
})();
回答by Eric Leschinski
The unresponsive script dialog box shows when some javascript thread takes too long too complete. Editing the registry could work, but you would have to do it on all client machines. You could use a "recursive closure" as follows to alleviate the problem. It's just a coding structure in which allows you to take a long running for loop and change it into something that does some work, and keeps track where it left off, yielding to the browser, then continuing where it left off until we are done.
无响应脚本对话框显示某些 javascript 线程耗时太长太完整。编辑注册表可以工作,但您必须在所有客户端计算机上执行此操作。您可以使用如下的“递归闭包”来缓解这个问题。它只是一种编码结构,它允许您长时间运行 for 循环并将其更改为可以执行某些工作的内容,并跟踪它停止的地方,让步给浏览器,然后从停止的地方继续,直到我们完成。
Figure 1, Add this Utility Class RepeatingOperation to your javascript file. You will not need to change this code:
图 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();
};
};
Figure 2, The following code represents your code that is causing the 'stop running this script' dialog because it takes so long to complete:
图 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.
}
}
Figure 3. The following code is the fix for the problematic code in Figure 2. Notice the for loop is replaced with a recursive closure which passes control back to the browser every 10 iterations of heavytask()
图 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.
};
Adapted from this source:
改编自此来源:
回答by vinesh
In my case, while playing video, I needed to call a function everytime currentTime
of video updates. So I used timeupdate
event of video and I came to know that it was fired at least 4 times a second (depends on the browser you use, see this). So I changed it to call a function every second like this:
就我而言,在播放视频时,每次currentTime
视频更新时我都需要调用一个函数。所以我使用timeupdate
了视频事件,我知道它每秒至少被触发 4 次(取决于您使用的浏览器,请参阅此)。所以我把它改成每秒调用一个函数,如下所示:
var currentIntTime = 0;
var someFunction = function() {
currentIntTime++;
// Do something here
}
vidEl.on('timeupdate', function(){
if(parseInt(vidEl.currentTime) > currentIntTime) {
someFunction();
}
});
This reduces calls to someFunc
by at least 1/3
and it may help your browser to behave normally. It did for me !!!
这someFunc
至少1/3
可以减少对 的调用,并且可以帮助您的浏览器正常运行。它对我有用!!!
回答by Matt Campbell
I can't comment on the previous answers since I haven't tried them. However I know the following strategy works for me. It is a bit less elegant but gets the job done. It also doesn't require breaking code into chunks like some other approaches seem to do. In my case, that was not an option, because my code had recursive calls to the logic that was being looped; i.e., there was no practical way to just hop out of the loop, then be able to resume in some way by using global vars to preserve current state since those globals could be changed by references to them in a subsequent recursed call. So I needed a straight-forward way that would not offer a chance for the code to compromise the data state integrity.
我无法对以前的答案发表评论,因为我还没有尝试过。但是我知道以下策略对我有用。它不太优雅,但可以完成工作。它也不需要像其他一些方法似乎做的那样将代码分成块。就我而言,这不是一个选项,因为我的代码对正在循环的逻辑进行了递归调用;即,没有实用的方法可以跳出循环,然后能够通过使用全局变量以某种方式恢复以保留当前状态,因为这些全局变量可以通过在随后的递归调用中引用它们来更改。所以我需要一种不会让代码有机会破坏数据状态完整性的直接方法。
Assuming the "stop script?" dialog is coming up during a for() loop executuion after a number of iterations (in my case, about 8-10), and messing with the registry is no option, here was the fix (for me, anyway):
假设“停止脚本?” 在多次迭代(在我的情况下,大约 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()