如何阻止激烈的Javascript循环冻结浏览器
我正在使用Javascript解析一个包含3500个元素的XML文件。我使用的是jQuery“each”函数,但我可以使用任何形式的循环。如何阻止激烈的Javascript循环冻结浏览器,javascript,jquery,performance,loops,Javascript,Jquery,Performance,Loops,我正在使用Javascript解析一个包含3500个元素的XML文件。我使用的是jQuery“each”函数,但我可以使用任何形式的循环。 问题是当循环执行时,浏览器会冻结几秒钟。停止冻结浏览器而不使代码速度过慢的最佳方法是什么 $(xmlDoc).find("Object").each(function() { //Processing here }); 设置处理之间的超时,以防止循环占用所有浏览器资源。总的来说,只需几秒钟就可以处理和循环所有内容,这对于3500个元件来说并不合理
问题是当循环执行时,浏览器会冻结几秒钟。停止冻结浏览器而不使代码速度过慢的最佳方法是什么
$(xmlDoc).find("Object").each(function() {
//Processing here
});
设置处理之间的超时,以防止循环占用所有浏览器资源。总的来说,只需几秒钟就可以处理和循环所有内容,这对于3500个元件来说并不合理
var xmlElements = $(xmlDoc).find('Object');
var processing = function() {
var element = xmlElements.shift();
//process element;
if (xmlElements.length > 0) {
setTimeout(processing, 5);
}
}
processing();
Javascript是单线程的,所以除了
setTimeout
,您可以做的不多。如果使用谷歌Goice是您站点的一种选择,它们提供了在真实背景线程中运行JavaScript的能力。 < P>我将考虑将这3500个元素从XML转换为JSON服务器端,或者更好地将其上传到服务器转换,以便其原生于GETGO的JS。
这将最大限度地减少您的负载并使文件大小变小。您可以使用HTML5 workers API,但这只适用于Firefox 3.1和Safari 4 betas atm。您可以将超时()设置为零,并且它将根据需要生成。我会放弃“each”函数,而使用for循环,因为它更快。我还将使用“setTimeout”添加一些等待,但仅在需要时每隔一段时间添加一次。您不希望每次等待5毫秒,因为处理3500条记录大约需要17.5秒 下面是一个使用for循环的示例,该循环以5毫秒的间隔处理100条记录(您可以调整它),这会产生175毫秒的开销
var xmlElements = $(xmlDoc).find('Object');
var length = xmlElements.length;
var index = 0;
var process = function() {
for (; index < length; index++) {
var toProcess = xmlElements[index];
// Perform xml processing
if (index + 1 < length && index % 100 == 0) {
setTimeout(process, 5);
}
}
};
process();
希望这能有所帮助。长循环而不冻结浏览器可以使用Turboid框架。使用它,您可以编写如下代码:
loop(function(){
// Do something...
}, number_of_iterations, number_of_milliseconds);
这篇turboid.net文章中的更多细节:我遇到了与用户连续刷新页面时相同的问题。原因是发生了超过52000次的两个嵌套for循环。这个问题在Firefox24中比在Chrome29中更为严重,因为Firefox崩溃的速度更快(比Chrome快2000毫秒左右)。我只是简单地使用“for”循环,而不是每个循环,然后我重构代码,将整个循环数组划分为4个独立的调用,然后将结果合并为一个。这个解决方案已经证明它是有效的 大概是这样的:
// start benchmark
var t = new Date();
// some xml processing
console.log("Time to process: " + new Date() - t + "ms");
var entittiesToLoop = ["..."]; // Mainly a big array
loopForSubset(0, firstInterval);
loopForSubset(firstInterval, secondInterval);
...
var loopForSubset = function (startIndex, endIndex) {
for (var i=startIndex; i < endIndex; i++) {
//Do your stuff as usual here
}
}
var entittiesToLoop=[“…”];//主要是一个大数组
loopForSubset(0,firstInterval);
loopForSubset(第一个间隔,第二个间隔);
...
var loopForSubset=函数(startIndex,endIndex){
对于(var i=startIndex;i
另一个同样适用于我的解决方案是使用HTML5中的工作者API实现的相同解决方案。在workers中使用相同的概念,因为它们避免您的浏览器被冻结,因为它们在主线程的后台运行。如果仅将此应用于Workers API不起作用,请将loopForSubset
的每个实例放置在不同的Worker中,并将结果合并到Worker的主调用程序中
我的意思是,这可能并不完美,但这已经奏效了。如果有人仍然认为这可能适合他们,我可以帮助他们处理更真实的代码块。您可以尝试通过
$(xmlDoc).find("Object").each(function(arg1) {
(function(arg1_received) {
setTimeout(function(arg1_received_reached) {
//your stuff with the arg1_received_reached goes here
}(arg1_received), 0)
})(arg1)
}(this));
这不会对你造成多大伤害;) 作为@tj111的修改,回答完整的可用代码
//add pop and shift functions to jQuery library. put in somewhere in your code.
//pop function is now used here but you can use it in other parts of your code.
(function( $ ) {
$.fn.pop = function() {
var top = this.get(-1);
this.splice(this.length-1,1);
return top;
};
$.fn.shift = function() {
var bottom = this.get(0);
this.splice(0,1);
return bottom;
};
})( jQuery );
//the core of the code:
var $div = $('body').find('div');//.each();
var s= $div.length;
var mIndex = 0;
var process = function() {
var $div = $div.first();
//here your own code.
//progress bar:
mIndex++;
// e.g.: progressBar(mIndex/s*100.,$pb0);
//start new iteration.
$div.shift();
if($div.size()>0){
setTimeout(process, 5);
} else {
//when calculations are finished.
console.log('finished');
}
}
process();
学习一门更快的语言!不,真的:除非是绝对必要的,否则不要使用JS。正如你所看到的,它是1)单线程的,2)很慢。这是一个客户端函数,JS是必需的。@Triptych-他的选项是什么?当然,有人希望这样的繁重工作可以在服务器端完成,但由于我们不知道他的情况,最好假设他有充分的理由在客户端完成,当在web应用程序中使用客户端时,您实际上只能在Javascript和,嗯…之间进行选择。。。Javascript中繁重计算的最佳实践我决定使用这种方法,除了每隔50个元素运行setTimeout。是的,它的超时值为0。@Christoph-您不需要传递任何超时间隔“0”,因为默认值为0
。这是一个好主意-定期使用setTimeout。它的超时时间为0。我已经为几个需要在客户端进行海量数据处理的web应用程序完成了这项工作。工作起来很有魅力,即使它确实需要一些重构。很酷的代码。也许我遗漏了一些东西,但我必须在setTimeout()之后添加一个index++
和一个break
,以使其正常工作。我不知道我是否遗漏了一些东西,但根据您在此处提供的内容进行造型时,我的代码将以无限循环的方式运行。最好使用console.time()和console.timeEnd()对于基准测试,我同意Workers API,但不能从Worker API进行DOM操作