我正在维护不幸在IE8上运行的软件。 IE8的问题在于,如果同步执行太长,它会抛出“脚本无响应”错误:
当Internet Explorer达到一段JavaScript的最大同步指令数时,会显示此消息。 as described here
处理此问题的标准方法类似于
setTimeout(function(){ //slow code }, 1);
但是,在我的情况下,缓慢的部分实际上是:
jQuery(/*selectors*/).each()// iteration
如何审核jQuery().each()
找到的元素,其中实际的.each()
部分是以超时的方式递归执行的?即使each()
块没有任何作用,我仍然会收到弹出警告。有大约20,000个元素可以迭代...我知道......
如果不重写页面上的任何内容,最好的方法是什么(假设我真的无法重写20,000个元素表)。
答案 0 :(得分:2)
仅供参考,如果您的问题确实发生,因为此操作本身就是:
jQuery(selectors)
需要太长时间,然后您必须将选择器更改为以某种方式评估或更改HTML的速度更快的内容,以便您可以一次查询表的各个部分。 IE8中的jQuery可能会使用Sizzle库来评估选择器,所以如果你有一个大型HTML,选择器和Sizzle的组合对于IE8来说太慢了,那么你将不得不改变其中的一个。 / p>
我们无法在没有看到实际HTML的情况下帮助解决此问题的具体细节,并且可能需要某种测试平台进行试验。我的猜测是,可能有一个更好的选择器,可能使用本机支持的查询机制,如getElementsByTagName()
或类似的东西,但我们必须看到实际的HTML,以提出更具体的建议。正如您已经知道,在一个非常慢的浏览器中,20,000个元素只是一个糟糕的配方。
如果您通过选择器查找并且只想获得有关iteartion的帮助,则无法直接使用.each()
,因为它将一次运行。相反,您将不得不手动迭代DOM对象的jQuery列表。
function processLargeArray(items) {
// set check size to whatever number of items you can process at once
var chunk = 100;
var index = 0;
function doChunk() {
var cnt = chunk;
while (cnt-- && index < items.length) {
// process items.eq(index) here
++index;
}
if (index < items.length) {
// set Timeout for async iteration
setTimeout(doChunk, 1);
}
}
doChunk();
}
var data = jQuery(selectors);
processLargeArray(data);
仅供参考,此代码适用于jQuery对象,来自关于该主题的更通用的答案:Best way to iterate over an array without blocking the UI
这是一个使用jQuery插件创建类似.each()
接口的版本(但它是异步)。
jQuery.fn.eachChunk = function(chunk, eachFn, completeFn) {
var index = 0;
var obj = this;
function next() {
var temp;
if (index < obj.length) {
temp = obj.slice(index, index + chunk);
temp.each(eachFn);
index += chunk;
setTimeout(next, 1);
} else {
if (completeFn) {
completeFn();
}
}
}
next();
return this;
};
jQuery(selectors).eachChunk(100, yourFn);
答案 1 :(得分:1)
我非常喜欢Async Library:
https://github.com/caolan/async
为您提供了一系列运行顺序异步函数的选项。
async.each([..], function(callback){
// Iterator function
callback();
});
以与jQuery相同的方式工作,但与jQuery不同,您可以获得更多控制权,例如:
async.eachSeries([...], function(callback){
// Will handle each element one at a time
callback();
});
async.eachLimit,这意味着您可以控制在任何给定时间运行的任务数量 - 在任何给定时间并行运行x个任务;
所以,例如:
async.eachLimit([...], 2, function(callback){
// This will run the tasks simultaneously
callback();
});
将对数组中的所有元素运行迭代器函数,但会将并发运行的任务数限制为2.如果您需要4个任务,只需将第二个参数更改为4,等等......
所以,例如:
async.eachLimit([...], 2, function(callback){
// This will run up to 2 tasks simulatenously
callback(); // If successfull
});
如果您需要超时以使操作在超时后静默失败(超时的作业不会完成,并且队列的其余部分继续运行。
async.eachLimit([...], 2, function(callback){
// This will run up to 2 tasks simulatenously
callback(); // If successfull
setTimeout(function(){
return callback();
}, timeoutLength);
});
如果您需要超时以使操作无声地失败,(如果出现一个错误,一切都会停止)。
async.eachLimit([...], 2, function(callback){
// This will run up to 2 tasks simulatenously
callback(); // If successfull
setTimeout(function(){
return callback("Error");
}, timeoutLength);
});
我不确定您的工作的具体要求是什么,但我认为异步库是这类内容的理想选择,并且具有很多控制流程灵活性,可以完成您的工作。< / p>
答案 2 :(得分:0)
这是使用each
循环的一种jQuery方式:
(function () { //avoid global var for test
var $elems = $('selector'), // elements to iterate
chunk = 50; //number of elements before stoping iteration
(function doStuff() { //recursive method
$elems.each(function (i) {
//delaying method when needed
if (i && !(i%chunk)) {
$elems = $elems.slice(i);
setTimeout(doStuff, 1);
return false;
}
//do slow stuff HERE
//...
});
})();
})();