이벤트 루프 이해


135

나는 그것에 대해 생각하고 있으며 이것이 내가 생각해 낸 것입니다.

아래 코드를 보자 :

console.clear();
console.log("a");
setTimeout(function(){console.log("b");},1000);
console.log("c");
setTimeout(function(){console.log("d");},0);

요청이 들어오고 JS 엔진이 위의 코드를 단계별로 실행하기 시작합니다. 처음 두 통화는 동기화 통화입니다. 그러나 setTimeout메소드에 관해서 는 비동기 실행이됩니다. 그러나 JS 즉시에서 반환하고 호출되는, 실행을 계속 Non-Blocking하거나 Async. 그리고 다른 작업을 계속하고 있습니다.

이 실행 결과는 다음과 같습니다.

acdb

따라서 기본적으로 두 번째 setTimeout가 먼저 완료되고 콜백 함수가 첫 번째보다 먼저 실행되므로 의미가 있습니다.

여기서는 단일 스레드 응용 프로그램에 대해 이야기하고 있습니다. JS Engine은이를 계속 실행하며 첫 번째 요청을 완료하지 않으면 두 번째 요청으로 이동하지 않습니다. 그러나 좋은 점은 setTimeout해결 과 같은 블로킹 작업을 기다리지 않으므로 새로운 수신 요청을 수락하므로 더 빠릅니다.

그러나 내 질문은 다음 항목과 관련하여 발생합니다.

# 1 : 단일 스레드 응용 프로그램에 대해 이야기 setTimeouts하는 경우 JS 엔진이 더 많은 요청을 수락하고 실행하는 동안 어떤 메커니즘이 처리 됩니까? 단일 스레드가 다른 요청에서 어떻게 계속 작동합니까? setTimeout다른 요청이 계속 들어 와서 실행되는 동안 작동 하는 것.

# 2 :setTimeout 더 많은 요청이 들어오고 실행되는 동안 이러한 기능이 백그라운드에서 실행되면 백그라운드에서 비동기 실행이 수행되는 것은 무엇입니까? 우리가 말하는 것은 무엇입니까 EventLoop?

# 3 : 그러나 EventLoop모든 것이 실행되고 콜백 메소드가 호출되도록 전체 메소드를 넣지 않아야 합니까? 이것이 콜백 함수에 대해 이야기 할 때 이해하는 것입니다.

function downloadFile(filePath, callback)
{
   blah.downloadFile(filePath);
   callback();
}

그러나이 경우 JS 엔진은 콜백을 EventLoop? 에 넣을 수 있도록 비동기 함수인지 어떻게 알 수 있습니까? 아마도 asyncC # 의 키워드 또는 JS 엔진이 취할 메소드를 나타내는 속성의 일종과 같은 것이 비동기 메소드이므로 적절하게 처리해야합니다.

# 4 : 그러나 기사 는 일이 어떻게 진행 될지에 대해 내가 추측 한 것과는 매우 반대라고 말합니다.

이벤트 루프는 콜백 함수 대기열입니다. 비동기 함수가 실행되면 콜백 함수가 큐로 푸시됩니다. JavaScript 함수는 비동기 함수가 실행 된 후 코드가 실행될 때까지 이벤트 루프 처리를 시작하지 않습니다.

# 5 : 이 이미지가 도움이 될 수 있지만 이미지의 첫 번째 설명은 질문 번호 4에서 언급 한 것과 정확히 같은 내용입니다.

여기에 이미지 설명을 입력하십시오

그래서 내 질문은 위에 나열된 항목에 대한 설명을 얻는 것입니다.


1
스레드는 이러한 문제를 처리하기에 적합한 은유가 아닙니다. 이벤트를 생각하십시오.
Denys Séguret

1
@dystroy : JS의 이벤트 비유가보기 좋을 것임을 보여주는 코드 샘플.
Tarik

나는 당신의 질문이 정확히 무엇인지 알 수 없습니다.
Denys Séguret

1
@ dystroy : 내 질문은 위에 나열된 항목에 대한 설명을 얻는 것입니다.
Tarik

2
노드는 단일 스레드가 아니지만 중요하지 않습니다 (사용자 코드가 실행되는 동안 다른 작업을 수행한다는 사실은 제외). 사용자 코드에서 최대 하나의 콜백 만 한 번에 실행됩니다.
Denys Séguret

답변:


85

1 : 단일 스레드 응용 프로그램에 대해 이야기하는 경우 JS 엔진이 더 많은 요청을 수락하고 실행하는 동안 setTimeouts를 처리하는 것은 무엇입니까? 단일 스레드가 다른 요청에서 계속 작동하지 않습니까? 그러면 다른 요청이 계속해서 실행되는 동안 누가 setTimeout 작업을 계속할 것입니까

노드 프로세스에는 실제로 프로그램의 JavaScript를 실행하는 스레드가 하나뿐입니다. 그러나 노드 자체에는 실제로 이벤트 루프 메커니즘의 작동을 처리하는 여러 스레드가 있으며 여기에는 IO 스레드 풀과 소수의 다른 스레드가 포함됩니다. 핵심은 이러한 스레드 수가 연결 당 스레드 동시성 모델에서와 같이 처리되는 동시 연결 수에 해당하지 않는다는 것입니다.

이제 "setTimeouts 실행"에 대해 호출 setTimeout하면 모든 노드가 기본적으로 나중에 실행될 함수의 데이터 구조를 업데이트합니다. 기본적으로 수행해야 할 많은 대기열과 이벤트 루프의 모든 "틱"이 하나를 선택하여 대기열에서 제거하고 실행합니다.

이해해야 할 핵심은 노드가 대부분의 무거운 작업을 위해 OS에 의존한다는 것입니다. 따라서 들어오는 네트워크 요청은 실제로 OS 자체에 의해 추적되며 노드가 처리 할 준비가되면 시스템 호출을 사용하여 처리 할 데이터가있는 네트워크 요청을 OS에 요청하기 만하면됩니다. IO "작업"노드의 많은 부분은 "Hey OS, 데이터를 읽을 수있는 네트워크 연결이 준비되어 있습니까?"입니다. 또는 "Hey OS, 미해결 파일 시스템 호출에 데이터가 준비되어 있습니까?" 내부 알고리즘 및 이벤트 루프 엔진 설계를 기반으로 노드는 JavaScript의 "틱"을 하나 선택하여 실행 한 다음 프로세스를 다시 반복합니다. 이것이 이벤트 루프의 의미입니다. 노드는 기본적으로 항상 "다음에 실행해야 할 JavaScript가 무엇입니까?"를 결정한 다음 실행합니다.setTimeout또는 process.nextTick.

2 : 더 많은 요청이 들어오고 실행되는 동안 이러한 setTimeout이 씬 뒤에서 실행되면 씬 뒤에서 비동기 실행을 수행하는 것은 EventLoop에 대해 이야기하는 것입니다.

뒤에서 JavaScript가 실행되지 않습니다. 프로그램의 모든 JavaScript는 한 번에 하나씩 앞뒤로 실행됩니다. 뒤에서 일어나는 일은 OS가 IO를 처리하고 노드는 준비가 될 때까지 대기하고 노드는 실행 대기중인 Javascript 대기열을 관리합니다.

3 : JS 엔진이 EventLoop에 넣을 수 있도록 비동기 함수인지 어떻게 알 수 있습니까?

노드 코어에는 시스템 호출을 수행하기 때문에 비동기 인 고정 함수 세트가 있으며 노드는 OS 또는 C ++를 호출해야하기 때문에 이것이 무엇인지 알고 있습니다. 기본적으로 모든 네트워크 및 파일 시스템 IO와 자식 프로세스 상호 작용은 비동기식이며 JavaScript는 노드 코어 라이브러리에서 제공하는 비동기 함수 중 하나를 호출하여 노드가 비동기 적으로 무언가를 실행할 수있는 유일한 방법입니다. 이벤트 루프를 생성하기 위해 자체 API를 정의하는 npm 패키지를 사용하는 경우에도 결국 npm 패키지의 코드는 노드 코어의 비동기 함수 중 하나를 호출하며 노드가 틱이 완료되었음을 알고 이벤트를 시작할 수있는 경우 루프 알고리즘을 다시 수행하십시오.

4 이벤트 루프는 콜백 함수 대기열입니다. 비동기 함수가 실행되면 콜백 함수가 큐로 푸시됩니다. JavaScript 함수는 비동기 함수가 실행 된 후 코드가 실행될 때까지 이벤트 루프 처리를 시작하지 않습니다.

예, 이것은 사실이지만 오해의 소지가 있습니다. 중요한 것은 정상적인 패턴입니다.

//Let's say this code is running in tick 1
fs.readFile("/home/barney/colors.txt", function (error, data) {
  //The code inside this callback function will absolutely NOT run in tick 1
  //It will run in some tick >= 2
});
//This code will absolutely also run in tick 1
//HOWEVER, typically there's not much else to do here,
//so at some point soon after queueing up some async IO, this tick
//will have nothing useful to do so it will just end because the IO result
//is necessary before anything useful can be done

예, 메모리에서 피보나치 수를 모두 같은 틱으로 동시에 계산하여 이벤트 루프를 완전히 차단할 수 있으며, 그래야 프로그램이 완전히 정지됩니다. 협력적인 동시성입니다. JavaScript의 모든 틱은 일정 시간 내에 이벤트 루프를 생성해야합니다. 그렇지 않으면 전체 아키텍처가 실패합니다.


1
서버를 실행하는 데 1 분이 걸리는 큐가 있다고 가정 해 보겠습니다. 첫 번째 것은 10 초 후에 완료되는 비동기 기능이었습니다. 대기열의 끝으로 이동합니까 아니면 준비가 된 즉시 회선으로 전달됩니까?
ilyo

4
일반적으로 대기열의 끝 부분으로 이동하지만 process.nextTickvs setTimeout대의 의미 setImmediate는 미묘하게 다르지만 실제로 신경 쓸 필요는 없습니다. 나는이 의 setTimeout과 친구라는 블로그 게시물 자세히로 들어갑니다.
피터 리용

자세히 설명해 주시겠습니까? 두 개의 콜백이 있고 첫 번째 콜백에는 실행 시간이 10mS이고 setTimeout이 1 분인 changeColor 메소드가 있고 두 번째 콜백에는 setTimeout이 10 초인 실행 시간이 50ms 인 changeBackground 메소드가 있다고 가정하겠습니다. 큐에 먼저 changeBackground가 있고 changeColor가 다음에 있다고 느낍니다. 그 후 Event 루프는 메소드를 동 기적으로 선택합니다. 내가 맞아?
SheshPai

1
@SheshPai 영어 단락으로 쓰여질 때 모든 사람들이 코드를 논의하는 것은 너무 혼란 스럽다. 코드 스 니펫을 사용하여 새로운 질문을 게시하면 사람들이 코드 설명 대신 코드를 기반으로 답변 할 수 있으므로 많은 모호함이 남습니다.
Peter Lyons

youtube.com/watch?v=QyUFheng6J0&spfreload=5 자바 스크립트 엔진에 대한 또 다른 좋은 설명입니다
Mukesh Kumar

65

필립 로버츠 (Philip Roberts)의 환상적인 비디오 튜토리얼이 가장 간단하고 개념적인 자바 스크립트 이벤트 루프를 설명합니다. 모든 자바 스크립트 개발자는 살펴 봐야합니다.

다음은 Youtube 의 비디오 링크 입니다.


16
나는 그것을 보았고 그것은 실제로 최고의 설명이었습니다.
Tarik

1
JavaScript 팬 및 애호가를위한 비디오를 시청해야합니다.
Nirus

1
이 비디오는 내 라이브를 변경합니다 ^^
HuyTran

1
여기 방황했습니다 .. 그리고 이것은 내가 얻은 최고의 설명 중 하나입니다. 공유해 주셔서 감사합니다 ... : D
RohitS

1
그것은 눈에 띄는 사람이었습니다
HebleV

11

호스트 프로세스가 단일 스레드라고 생각하지 마십시오. 단일 스레드는 Javascript 코드를 실행하는 호스트 프로세스 부분입니다.

백그라운드 근로자를 제외하고 는 시나리오가 복잡합니다.

따라서 모든 js 코드가 동일한 스레드에서 실행되므로 js 코드의 서로 다른 두 부분이 동시에 실행될 가능성이 없습니다 (따라서 동시성 관리가 필요하지 않음).

실행중인 js 코드는 호스트 프로세스가 이벤트 루프에서 선택한 마지막 코드입니다. 코드에서 기본적으로 두 가지 작업을 수행 할 수 있습니다. 동기 명령 실행 및 일부 이벤트가 발생할 때 나중에 실행되도록 함수 예약.

귀하의 예제 코드에 대한 내 정신 표현은 다음과 같습니다 (주의하십시오 : 브라우저 구현 세부 사항을 알지 못합니다!).

console.clear();                                   //exec sync
console.log("a");                                  //exec sync
setTimeout(                //schedule inAWhile to be executed at now +1 s 
    function inAWhile(){
        console.log("b");
    },1000);    
console.log("c");                                  //exec sync
setTimeout(
    function justNow(){          //schedule justNow to be executed just now
        console.log("d");
},0);       

코드가 실행되는 동안 호스트 프로세스의 다른 스레드는 발생하는 모든 시스템 이벤트 (UI 클릭, 파일 읽기, 수신 된 네트워크 패킷 등)를 추적합니다.

코드가 완료되면 코드가 이벤트 루프에서 제거되고 호스트 프로세스는 코드를 다시 검사하여 실행할 코드가 더 있는지 확인합니다. 이벤트 루프에는 두 개의 이벤트 핸들러가 더 있습니다. 하나는 지금 실행 (justNow 함수)하고 다른 하나는 1 초 내에 (inAWhile 함수) 처리합니다.

호스트 프로세스는 이제 처리기가 등록되어 있는지 확인하기 위해 발생한 모든 이벤트를 일치 시키려고합니다. justNow가 기다리는 이벤트가 발생 했으므로 코드를 실행하기 시작했습니다. justNow 함수가 종료되면 이벤트에 대한 핸들러를 찾기 위해 이벤트 루프를 다시 확인합니다. 1 초가 지났다고 가정하면 inAWhile 함수 등을 실행합니다.


그러나 setTimeout은 기본 스레드에서 구현됩니다. 따라서 예제에서 별도의 스레드가 필요한 것은 없습니다. 실제로 브라우저에서는 탭만 여러 스레드로 구현됩니다. 단일 탭에서 다중 병렬 네트워크 연결, 마우스 클릭 대기, setTimeout, 애니메이션 등을 포함한 모든 프로세스가 동일한 스레드에서 수행됩니다
slebetman
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.