Programing

강렬한 자바 스크립트 루프가 브라우저를 멈추는 것을 막는 방법

lottogame 2020. 12. 30. 07:39
반응형

강렬한 자바 스크립트 루프가 브라우저를 멈추는 것을 막는 방법


Javascript를 사용하여 약 3,500 개의 요소가있는 XML 파일을 구문 분석하고 있습니다. jQuery "각"함수를 사용하고 있지만 모든 형태의 루프를 사용할 수 있습니다.
문제는 루프가 실행되는 동안 브라우저가 몇 초 동안 멈춘다는 것입니다. 코드 속도를 너무 늦추지 않고 브라우저 정지를 중지하는 가장 좋은 방법은 무엇입니까?

$(xmlDoc).find("Object").each(function() {
    //Processing here
});

더 빠르기 때문에 for 루프에 찬성하여 "each"함수를 버릴 것입니다. 또한 "setTimeout"을 사용하여 약간의 대기 시간을 추가하지만 필요한 경우에만 그렇게 자주 추가합니다. 3500 개의 레코드를 처리하는 데 약 17.5 초가 걸리므로 매번 5ms를 기다리지 않아도됩니다.

다음은 175ms의 오버 헤드를 제공하는 5ms 간격으로 100 개의 레코드를 처리하는 for 루프를 사용하는 예입니다 (조정 가능).

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();

또한 수정 될 수있는 어딘가에 병목 현상이 있는지 확인하기 위해 xml 처리의 다른 부분을 벤치마킹합니다. firebug의 프로파일 러를 사용하고 다음과 같이 콘솔에 작성하여 firefox에서 벤치마킹 할 수 있습니다.

// start benchmark
var t = new Date();
// some xml processing
console.log("Time to process: " + new Date() - t + "ms");

도움이 되었기를 바랍니다.


처리 사이에 시간 제한을 설정하여 루프주기가 모든 브라우저 리소스를 소모하지 않도록합니다. 전체적으로 3,500 개의 요소에 대해 부당하지 않고 모든 것을 처리하고 반복하는 데 몇 초 밖에 걸리지 않습니다.

var xmlElements = $(xmlDoc).find('Object');

var processing = function() {
  var element = xmlElements.shift();

  //process element;

  if (xmlElements.length > 0) {
    setTimeout(processing, 5);
  }
}

processing();

3500 요소를 xml에서 JSON 서버 측으로 변환하거나 변환 된 서버에 더 잘 업로드하여 getgo에서 JS에 기본적으로 적용되도록 고려합니다.

이렇게하면로드가 최소화되고 파일 크기도 작아집니다.


Turboid 프레임 워크를 사용하면 브라우저를 고정하지 않고 긴 루프가 가능합니다. 이를 통해 다음과 같은 코드를 작성할 수 있습니다.

loop(function(){  
        // Do something...  
}, number_of_iterations, number_of_milliseconds);

이 turboid.net 기사에서 더 많은 세부 사항 : 자바 스크립트의 실제 루프


자바 스크립트는 단일 스레드이므로을 제외하고 setTimeout할 수있는 작업이 많지 않습니다. Google Gears를 사용하는 것이 사이트의 옵션 인 경우 진정한 백그라운드 스레드에서 자바 스크립트를 실행할 수있는 기능을 제공합니다.


ZERO 기간으로 setTimeout () 할 수 있으며 원하는대로 산출됩니다.


HTML5 작업자 API를 사용할 수 있지만 Firefox 3.1 및 Safari 4 베타 atm에서만 작동합니다.


사용자가 페이지를 연속적으로 새로 고칠 때 발생하는 동일한 문제가 발생했습니다. 그 이유는 52000 회 이상 발생한 두 개의 중첩 for 루프 때문입니다. 이 문제는 Firefox가 더 빨리 충돌하기 때문에 (Chrome보다 약 2000ms 더 빠름) Chrome 29보다 Firefox 24에서 더 가혹했습니다. 내가 간단하게했고 효과가있는 것은 각각 대신 "for"루프를 사용하고 코드를 리팩토링하여 전체 루프 배열을 4 개의 분리 된 호출로 나누고 결과를 하나로 병합했습니다. 이 솔루션은 효과가 있음을 입증했습니다.

이 같은:

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
    }
}

The other solution which also worked for me was the same solution implemented with Worker APIs from HTML5. Use the same concept in workers as they avoid your browser to be frozen because they run in the background of your main thread. If just applying this with Workers API did not work, place each of instances of loopForSubset in different workers and merge the result inside the main caller of Worker.

I mean this might not be perfect but this has worked. I can help with more real code chunks, if someone still thinks this might suite them.


You could try shortening the code by

   $(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));

This won't harm you much ;)


As a modification of @tj111 answer the full usable code

    //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();

ReferenceURL : https://stackoverflow.com/questions/714942/how-to-stop-intense-javascript-loop-from-freezing-the-browser

반응형