如何阻止激烈的Javascript循环冻结浏览器

如何阻止激烈的Javascript循环冻结浏览器,javascript,jquery,performance,loops,Javascript,Jquery,Performance,Loops,我正在使用Javascript解析一个包含3500个元素的XML文件。我使用的是jQuery“each”函数,但我可以使用任何形式的循环。 问题是当循环执行时,浏览器会冻结几秒钟。停止冻结浏览器而不使代码速度过慢的最佳方法是什么 $(xmlDoc).find("Object").each(function() { //Processing here }); 设置处理之间的超时,以防止循环占用所有浏览器资源。总的来说,只需几秒钟就可以处理和循环所有内容,这对于3500个元件来说并不合理

我正在使用Javascript解析一个包含3500个元素的XML文件。我使用的是jQuery“each”函数,但我可以使用任何形式的循环。
问题是当循环执行时,浏览器会冻结几秒钟。停止冻结浏览器而不使代码速度过慢的最佳方法是什么

$(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操作