2011-07-27 6 views
3

내가이 함수에 전달있어 함수가있는 경우 : (. 그들의 숫자와 work 전화의 번호가있을 수 있습니다)비동기 작업의 끝을 결정하는 자바 스크립트

function(work) { 
    work(10); 
    work(20); 
    work(30); 
} 

work 성능 일부 비동기 액티비티 (예 :이 예에서는 timeout)입니다. 나는이 작업의 완료시에 work이하는 일 (실제로는 일반적으로 그 정의)을 완전히 제어 할 수 있습니다.

work에 대한 모든 호출이 완료되면 가장 좋은 결정 방법은 무엇입니까?


내 현재의 방법은 작업이 호출되는 카운터를 증가하고 완료 될 때를 감소시키고, 카운터 (이 모든 이후 감소 판정) 0 일 때 all work done 이벤트가 발생. 그러나, 나는 이것이 일종의 경쟁 조건이 될 수 있다고 걱정한다. 그게 아니라면 내 이유를 보여 주면 큰 도움이 될 것입니다.

+0

이것은 적어도 고려해야 할 사항입니다. http : //www.benjiegillam.co.kr/2011/11/multiple-asynchronous-callbacks/ –

답변

2

.

기억해야 할 중요한 점은 자바가 단일 스레드에서 실행되기 때문입니다. 이것은 모든 브라우저와 node.js AFAIK에 해당됩니다.

  1. 함수 (일)
  2. 워크 (10)
  3. 카운터 ++
  4. 다음 JS 이벤트 루프가 같은 순서로 기능을 수행하므로 이하 사려 코멘트 기준

    은 용액 작동
  5. 시작 비동기 기능
  6. 작업 (20)
  7. 카운터 ++
  8. 시작 비동기 기능
  9. 작업 (30)
  10. 카운터 ++
  11. 시작 비동기 기능
  12. - 다시 이벤트 루프 밖으로 -
  13. 비동기 기능이
  14. counter--
  15. 을 완료 - 이벤트 루프로 복귀 -
  16. 비동기 기능 완료
  17. 카운터 -
  18. - 다시 이벤트 루프 밖으로 - 다시 이벤트 루프 밖으로 - -
  19. 비동기 기능을 사용하면 작업 메시지
  20. 을 수행 발사 있도록
  21. counter--
  22. 카운터가 0이 완료
+0

단일 스레드가 이것이 작동한다는 것을 의미하는 이유는 무엇입니까? 멀티 스레드 환경에서 카운터의 문제점은 무엇입니까? – davin

+0

@davin 카운터는 모든 작업이 완료되기 전에 로컬 최소값이 '0'으로 기록 될 수 있습니다. 나는. doWork (3) – Raynos

+0

여러 스레드에서 카운터에 액세스하는 경우 카운터가 원자 적으로 업데이트되고 있음을 보장해야합니다. 일부 언어에서는 ++ 또는 i-- 변수가 읽기 및 설정과 관련된 작업이기 때문에 원자적인 것으로 보장되지 않습니다. 이것은 다중 쓰레드 환경에서 쓰레드 스케줄러의 자비에 그것을 둔다. @Raynos가 지적한 것과 같이 사용 사례에 따라 한 번에 여러 스레드가 실행되는 것과 관련된 다른 고려 사항이있을 수 있습니다. – Mike

2

경쟁 조건이 없습니다. 작업이 끝나면 감소를 수행하라는 요청마다 추가 요구 사항이 있습니다 (! 항상 http 오류가 포함 된 포함). 그러나 이는 호출을 감싸는 방식으로보다 캡슐화 된 방식으로 처리 될 수 있습니다.

테스트되지 않은,하지만이 요점이다 (I 대신 카운터의 객체를 구현, 그래서 이론적으로 특정 요청에 대한보다 세부적인 쿼리하려면이를 확장 할 수 있습니다) :

var ajaxWrapper = (function() { 
    var id = 0, calls = {}; 
    return { 
     makeRequest: function() { 
     $.post.apply($, arguments); // for example 
     calls[id] = true; 
     return id++; 
     }, 
     finishRequest: function(id) { 
     delete calls[id]; 
     }, 
     isAllDone: function(){ 
     var prop; 
     for(prop in calls) { 
      if(calls.hasOwnProperty(prop)) {return false;} 
     } 
     return true; 
     } 
    }; 
})(); 

사용법 :

를 당신은 당신이,541에 전화를 추가 할 수 있습니다 더 정교하고 싶었다면

대신 $.post("url", ... function(){ /*success*/ } ...);의 우리는

var requestId; 
requestId = ajaxWrapper.makeRequest("url", ... 
    function(){ /*success*/ ajaxWrapper.finishRequest(requestId); } ...); 

을 다하겠습니다 사용이 거의 완전히 투명하게 될 것이다자신이 래퍼 내부 : 그래서,

이 프로그램을 작성할 수있는 방법의 톤,하지만 잘 작동하는 카운터를 사용하여 간단한 기술이있다
ajaxWrapper.makeRequest("url", ... function(){ /*success*/ } ...); 
1

나는 유틸리티 기능이 after입니다.

var after = function _after(count, f) { 
    var c = 0, results = []; 
    return function _callback() { 
    switch (arguments.length) { 
     case 0: results.push(null); break; 
     case 1: results.push(arguments[0]); break; 
     default: results.push(Array.prototype.slice.call(arguments)); break; 
    } 
    if (++c === count) { 
     f.apply(this, results); 
    } 
    }; 
}; 

다음 코드는 작동합니다. 왜냐하면 자바 스크립트는 단일 스레드이기 때문입니다.

function doWork(work) { 
    work(10); 
    work(20); 
    work(30); 
} 

WorkHandler(doWork); 

function WorkHandler(cb) { 
    var counter = 0, 
     finish; 
    cb(function _work(item) { 
    counter++; 
    // somethingAsync calls `finish` when it's finished 
    somethingAsync(item, function _cb() { 
     finish() 
    }); 
    }); 
    finish = after(counter, function() { 
    console.log('work finished'); 
    }); 
}; 

내가 설명해야 할 것 같네.

우리는 작업 기능을 작업 처리기로 전달합니다.

작업 처리기가이를 호출하고 작업을 전달합니다. 회사 전화가 작업을 수행하는 기능이 있기 때문에 카운터

를 증가 여러 번 작동하지

기능은 비동기없는이 완료 후 (매우 중요) 우리가 마무리 기능을 정의 할 수 있습니다.

수행중인 비동기 작업은 현재 동기 작업 블록 (전체 작업 처리기의 실행)이 완료되기 전에 완료 할 수없고 정의되지 않은 종료 기능을 호출 할 수 없습니다.

이는 전체 작업 처리기가 완료된 후 (변수 완료가 설정된 경우) 비동기 작업 작업이 끝나고 finish를 호출 함을 의미합니다. 모든 전화가 완료되면 콜백이 after 번으로 전송됩니다.

관련 문제