2016-07-04 1 views
0

나는 비 블로킹/비동기 함수를 생성하기 위해 setTimeout을 사용하는 것이 중요하다고 언급 한 기사를 읽었습니다. 그리고 나는 setTimeout에 전달 된 함수가 백그라운드에서 실행된다고 생각했습니다. 그런 다음 다른 기사에서 setTimeout은 함수가 실행될 때 이벤트 루프를 차단합니다. 그래서, 다음과 같은 함수를 테스트 해 보았습니다. 1000MS 통과하고 기능을 실행하는 시간 때setTimeout blocks eventloop

function getit(cb) { 
var i = 0; 
setTimeout(function() { 
    while (i < 200000) { i++; console.log(i); } 
    cb(i); 
} , 1000); 
console.log(i); 
} 

getit(function(message) { console.log(message); }); 

분명히, 스레드가 차단 및 브라우저가 정지됩니다. 내 질문은, 비동기 코드가 스레드를 차단하도록되어 있지 않은 경우, 시간이 지났을 때 함수가 실행 중일 때 어떻게 가능하고 배경이 아닌지? 이것은 단지 지연 일 뿐인 것처럼 보이지만 결국 함수는 한 줄씩 실행되고 어쨌든 루프를 차단합니다. 내가 놓치거나 혼란에 빠진 것이 있습니까?

+0

'setTimeout()'은 나중에 실행될 함수를 대기열에 올려 놓고 * current * 함수의 실행을 차단하지 않습니다. 그것은 "배경"에 대기중인 기능을 실행하거나 그것에 대한 새 스레드를 만들지 않습니다. (당신이 브라우저가 멈추는 것을 말한다면, node.js 태그는 무엇입니까?) – nnnnnn

+1

https://nodesource.com/blog/understanding-the-nodejs-event-loop/ – Sreevisakh

+0

그러나 스레드가 실행될 때 스레드를 차단합니까? 주어진 코드에서 보여주는 것처럼? 나는 그것이 현재 실행을 차단하지 않는다는 것을 이해하지만 setTimeout 내부에서 함수를 실행할 시간이되면 스레드를 차단합니까? 이 기능이 실행되는 동안 다른 기능을 실행할 수 없습니다. –

답변

2

먼저 대부분의 상황에서 JavaScript는 단일 스레드임을 이해해야합니다. 비동기식이든 아니든 스크립트가 실행되면 모든 것을 차단합니다.

위 예제는 1000ms 후 busy-while 루프로 들어가고 다른 실행을 막기 시작합니다.

이를 해결하기 위해 다른 작업의 경우 "busy"실행주기 (Java 용어) 실행주기로 분주해야합니다.

예컨대 :

function getit(cb) { 
 
     setTimeout(function() { 
 
      lessBlockingGetIt(cb); 
 
     } , 1000); 
 
    } 
 
    
 
    // Note that this is only less blocking, and much slower 
 
    function lessBlockingGetIt(cb) { 
 
    
 
     // Instead of directly looping, we batch-loop with a setTimeout 
 
     var numberOfTimes = 1000; // Reduced the size so it doesn't block like forever 
 
     var batchSize = 10; 
 
    
 
     function executeBatch(start) { 
 
    
 
      // We use a zero-timeout function is achieve a "yield" behavior so other tasks in the event loop can execute 
 
      setTimeout(function(){ 
 
       var i = start, j; 
 
       for(j = 0; i < numberOfTimes && j < batchSize; i++, j++){ 
 
        console.log(i); 
 
       } 
 
       if(i < numberOfTimes){ 
 
        executeBatch(i); 
 
       } else { 
 
        cb(i); 
 
        console.log(i); 
 
       } 
 
      }, 0); 
 
    
 
     } 
 
     
 
     // Start the recursion loop 
 
     executeBatch(0); 
 
    
 
    } 
 
    
 
    getit(function(message) { console.log(message); });

는 그러나 실행이 훨씬 느립니다 알 것이고, 브라우저 그렇지 않으면 진정한 멀티 스레딩보다 분명히 덜 반응한다.

실제 멀티 스레딩을 달성하기 위해, 다음과 같은 코드로 웹 근로자 http://www.w3schools.com/html/html5_webworkers.asp

+0

오, 이제 이해합니다. 나는 NodeJS와 JS를 혼동했다. 나는 비동기 아이디어가 양쪽에 적용된다고 생각했다. 따라서 nodej를 통해 동일한 코드를 사용하면 서버 스레드가 차단되지 않습니다. –

+0

동일한 코드를 실행하면 ** 차단됩니다. 'console.log' 블록으로 여러 번 while-looping하기 때문에 차단합니다. – kazenorin

1

Node.js를 실행 모델이 표현 될 수를 사용해야합니다 :

function main() { 
    while(running) { 
    var timerCb = getNextTimedoutCallback(); 
    if(timerCb) timerCb(); // execute it 

    var ioCb = getNextCompleteIOOperationCallback(); 
    if(ioCb) ioCb(); // execute it 
    } 
} 

모든 단일 스레드에서 실행됩니다. IO 작업은 작업자 스레드에서 실행되고 완료된 IO 작업의 내부 큐를 채 웁니다. 그 getNextCompleteIOOperationCallback(); 그냥 큐에서 완료된 작업을 가져옵니다.

마찬가지로, setTimeout()은 기능을 종료 시간과 함께 타이머 대기열 (종료 시간 순서)에 푸시합니다. getNextTimedoutCallback()은 만료 된 다음 시간 초과를 가져옵니다 (있는 경우).

타이머 기능이나 IO 콜백 중 하나를 보면 알 수 있듯이 모든 것을 차단할 수 있습니다. 이것은 cooperative multitasking입니다.