2016-06-21 2 views
2

데이터 세트가 있는데,이 세트를 통해 각 요소에 대해 상당히 많은 연산을 반복 실행합니다. 브라우저가 멈추는 것을 막기 위해 시간 제한을 0ms로 설정했습니다. 브라우저가 멈추지는 않지만 계산은 사용자 입력에 따라 몇 초가 걸릴 수 있습니다. 여기에 코드입니다 : 이제외부에서 루프를 끊기

function calculation(){ 
    $.each(data,function(key,value){ 
     setTimeout(function(){ 
      doTheHeavyLifting(value); 
     },0); 
    }); 
} 

, 문제는 내가 사용자의 요청이 새 값으로 다시 계산을 실행하는 경우 이전 계산을 중지 할 것인지이다. I 함수 외부 continueCalculating 부울 정의, runCalculation()false-calculation() 호출 전에 calculation()true 내부로 다시 리셋하는 것으로 설정하려고

. 수정 된 코드는 다음과 같습니다.

var continueCalculating=false; 

function runCalculator(){ 
    continueCalculating=false; 
    calculation(); 
} 

function calculation(){ 
    continueCalculating=true; 
    $.each(data,function(key,value){ 
     setTimeout(function(){ 
      if(continueCalculating){ 
       doTheHeavyLifting(value); 
      }else{ 
       console.log("Abort the mission!"); 
       return false; 
      } 
     },0); 
    }); 
} 

글쎄, 그 트릭을하지 않았고, 회상에서 어쨌든 꽤 바보 같은 생각이었습니다. 그래서, 다음으로 나는 모든 타임 아웃을 지우려고했다. 수정 된 코드는 다음과 같습니다.

var continueCalculating=false; 
var operationQueue=[]; 

function runCalculator(){ 
    continueCalculating=false; 
    $.each(operationQueue, function(k,v){ 
     clearTimeout(v); 
    }); 
    calculation(); 
} 

function calculation(){ 
    continueCalculating=true; 
    $.each(data,function(key,value){ 
     operationQueue.push(setTimeout(function(){ 
      if(continueCalculating){ 
       doTheHeavyLifting(value); 
      }else{ 
       console.log("Abort the mission!"); 
       return false; 
      } 
     },0)); 
    }); 
} 

글쎄, 그 결과도 없습니다.

나는 이보다 느리지 만, 반복 할 항목이 약 12 ​​개 밖에 없으므로 여기에는 병목이 없습니다. 나는이 코드를 최적화 할 방법을 찾고 있지 않다. 계속 진행되는 계산을 중단해야한다. 이것이 가능한가?

+1

여기 루프를 사용해서는 안됩니다. 항목의 처리를 중단 시키려면 한 번에 하나의 항목을 처리하고 중간에 "시간을 주어야"다른 코드가 프로세스를 중단해야합니다. 기본적으로'setTimeout'을 사용하는 재귀 함수가 필요합니다. –

답변

2

당신은 비동기 적으로 반복해야합니다

var data = [0,1,2,3,4,5,6,7,8,9,"end"]; 
 
function doTheHeavyLifting(value) { 
 
    console.log(value); 
 
} 
 
function calculation(data) { 
 
    var key = 0, timer; 
 
    (function loop() { 
 
    if(key < data.length) { 
 
     doTheHeavyLifting(data[key]); 
 
     key++; 
 
     timer = setTimeout(loop, 1e3); 
 
    } 
 
    })(); 
 
    return {stop: function() { clearTimeout(timer) } }; 
 
} 
 
var calc = calculation(data); 
 
document.querySelector('#stop').onclick = calc.stop;
<button id="stop">Stop</button>

+0

정말 멋집니다. 필자는 항상 비동기 함수가 주기적으로 이와 같은 것을 수행하기 위해 검사하는 전역 플래그를 사용했지만 여기서는 전역 범위를 오염시키지 않고 루프마다 플래그를 확인하지 않아도되며 예제는 명확하고 쉽게 따를 수 있습니다. +1 – chiliNUT

0

당신은 $.queue(), $.Deferred()를 사용할 수 .promise()

// check at `if` condition within deferred 
 
var stop = false; 
 
$("button").on("click", function() { 
 
    // clear `"calculation"` queue at `click` event at `button` element 
 
    $.queue(data, "calculation", []); 
 
    // set `stop` to `true` at `click` event at `button` 
 
    stop = true; 
 
}); 
 
// `data` 
 
var data = Array(100).fill(0).map((v, k) => k); 
 

 
function doTheHeavyLifting(val) { 
 
    console.log(val); 
 
    // return `.promise()` when process within `doTheHeavyLifting` completes 
 
    return $("body").append("\n" + val).promise() 
 
} 
 

 
function calculation() { 
 
    $.queue(data, "calculation", $.map(data, function(value, index) { 
 
    return function(next) {  
 
     return new $.Deferred(function(dfd) { 
 
     setTimeout(function() { 
 
      if (!stop) { 
 
      dfd.resolve(doTheHeavyLifting(value)) 
 
      } else { 
 
      dfd.rejectWith(
 
       $.queue(data, "calculation") 
 
       , ["queue stopped at " + index] 
 
      ); 
 
      } 
 
     },0) 
 
     }) 
 
     // iterate next item in `data` 
 
     .then(next) 
 
     // do stuff if `"calculation"` queue is empty array 
 
     .fail(function(message) { 
 
     console.log(message 
 
        , "calculation queue:", this); 
 
     alert(message);    
 
     }) 
 
    } 
 
    })); 
 
    // start queue 
 
    $.dequeue(data, "calculation"); 
 
} 
 

 
calculation();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"> 
 
</script> 
 
<button>stop calculation</button>