소개
JavaScript는 대부분 Node.js와 브라우저의 단일 스레드에서 실행됩니다(현재 기사의 범위를 벗어나는 작업자 스레드와 같은 일부 예외는 있음). 이번 글에서는 Event Loop인 Node.js의 동시성 메커니즘을 설명하려고 합니다.
이 기사를 읽기 전에 스택과 작동 방식에 대해 잘 알고 있어야 합니다. 과거에 이 아이디어에 대해 쓴 적이 있으므로 스택 및 힙을 확인하세요. — 이해하지 않고 코딩을 시작하지 마세요 — Moshe Binieli | 중간
소개 이미지
예시
예제를 통해 학습하는 것이 가장 좋다고 생각하므로 간단한 코드 예제 4개부터 시작하겠습니다. 예제를 분석한 다음 Node.js의 아키텍처에 대해 자세히 살펴보겠습니다.
예 1:
console.log(1);
console.log(2);
console.log(3);
// 출력:
// 1
// 2
// 3
이 예제는 매우 쉬운 예입니다. 첫 번째 단계에서는 console.log(1)가 호출 스택으로 들어가서 실행된 다음 제거되고, 두 번째 단계에서는 console.log(2)가 호출 스택으로 들어가서 실행됩니다. 그런 다음 console.log(3)에 대해 제거하는 등의 작업을 수행합니다.
예제 1의 호출 스택 시각화
예시 2:
console.log(1);
setTimeout(함수 foo(){
console.log(2);
}, 0);
console.log(3);
// 출력:
// 1
// 3
// 2
이 예에서는 setTimeout을 바로 실행하는 것을 볼 수 있으므로 console.log(2)가 console.log(3)보다 앞에 있을 것으로 예상하지만 이는 사실이 아니며 그 뒤에 있는 메커니즘을 이해해 보겠습니다.
기본 이벤트 루프 아키텍처(나중에 자세히 살펴보겠습니다.)
스택 및 힙: 이에 대한 내 기사를 확인하세요(이 기사의 시작 부분에 링크를 추가했습니다)
Web Apis: 웹 브라우저에 내장되어 있으며 브라우저와 주변 컴퓨터 환경의 데이터를 노출하고 이를 통해 유용하고 복잡한 작업을 수행할 수 있습니다. 이는 JavaScript 언어 자체의 일부가 아니라 핵심 JavaScript 언어 위에 구축되어 JavaScript 코드에서 사용할 수 있는 추가 초능력을 제공합니다. 예를 들어 Geolocation API는 위치 데이터를 검색하기 위한 몇 가지 간단한 JavaScript 구성을 제공하므로 Google 지도에 위치를 표시할 수 있습니다. 백그라운드에서 브라우저는 실제로 일부 복잡한 하위 수준 코드(예: C++)를 사용하여 장치의 GPS 하드웨어(또는 위치 데이터를 결정하는 데 사용할 수 있는 모든 것)와 통신하고, 위치 데이터를 검색하고, 이를 브라우저 환경에 반환하여 사용합니다. 귀하의 코드에서. 그러나 API를 통해 이러한 복잡성이 추상화됩니다.
이벤트 루프 및 콜백 큐: Web Apis 실행을 마친 함수는 콜백 큐로 이동됩니다. 이는 일반적인 큐 데이터 구조이며, 이벤트 루프는 콜백 큐에서 다음 함수를 빼내고 해당 함수를 함수를 실행하기 위한 호출 스택입니다.
집행순서
현재 호출 스택에 있는 모든 함수가 실행된 후 호출 스택에서 제거됩니다.
콜 스택이 비어 있으면 대기 중인 모든 작업이 하나씩 콜 스택에 팝되어 실행된 후 콜 스택에서 팝됩니다.
예시 2를 이해해 봅시다
console.log(1) 메소드가 호출되어 콜 스택에 배치되어 실행됩니다.
setTimeout 메서드가 호출되어 호출 스택에 배치되고 실행되면 이 실행은 완료되면 0밀리초 동안 setTimeout Web Api에 대한 새 호출을 생성합니다(즉시 또는 더 정확하게 말하면 "가능한 한 빨리"라고 말하는 것이 좋습니다) Web Api는 호출을 콜백 대기열로 이동합니다.
console.log(3) 메소드가 호출되어 콜 스택에 배치되어 실행됩니다.
이벤트 루프는 콜 스택이 비어 있음을 확인하고 콜백 큐에서 "foo" 메소드를 꺼내 콜 스택에 배치한 후 console.log(2)가 실행됩니다.
예제 2의 프로세스 시각화
따라서 setTimeout(function, Delay)의 지연 매개변수는 함수가 실행된 후의 정확한 시간 지연을 나타내지 않습니다. 이는 특정 시점에 함수가 실행될 때까지 기다려야 하는 최소 시간을 나타냅니다.
예 3:
console.log(1);
setTimeout(function foo() {
console.log('foo');
}, 3500);
setTimeout(함수 boo() {
console.log('부');
}, 1000);
console.log(2);
// 출력:
// 1
// 2
// '부'
// '푸'
예제 3의 프로세스 시각화
예시 4:
console.log(1);
setTimeout(function foo() {
console.log('foo');
}, 6500);
setTimeout(함수 boo() {
console.log('부');
}, 2500);
setTimeout(함수 baz() {
console.log('baz');
}, 0);
for (['A', 'B']의 상수 값) {
console.log(값);
}
함수 2() {
console.log(2);
}
둘();
// 출력:
// 1
// '아'
// 'B'
// 2
// '바즈'
// '부'
// '푸'
예제 4의 프로세스 시각화
이벤트 루프는 작업 대기열에서 대기 중인 모든 콜백을 실행하기 위해 진행됩니다. 작업 대기열 내 작업은 크게 마이크로 작업과 매크로 작업이라는 두 가지 범주로 분류됩니다.
매크로 작업(작업 대기열) 및 마이크로 작업
더 정확하게 말하면 실제로는 두 가지 유형의 대기열이 있습니다.
매크로 작업 대기열과 마이크로 작업 대기열에 포함되는 작업이 몇 가지 더 있지만 일반적인 작업만 다루겠습니다.
일반적인 매크로 작업은 setTimeout, setInterval 및 setImmediate입니다.
일반적인 마이크로 작업은 process.nextTick 및 Promise 콜백입니다.
집행순서
현재 호출 스택에 있는 모든 함수가 실행된 후 호출 스택에서 제거됩니다.
콜 스택이 비어 있으면 대기 중인 모든 마이크로 태스크가 하나씩 콜 스택에 팝되어 실행된 다음 콜 스택에서 팝됩니다.
콜 스택과 마이크로 태스크 큐가 모두 비어 있으면 큐에 있는 모든 매크로 태스크가 하나씩 콜 스택에 팝되어 실행된 다음 콜 스택에서 팝됩니다.
예시 5:
console.log(1);
setTimeout(function foo() {
console.log('foo');
}, 0);
Promise.resolve()
.then(함수 boo() {
console.log('부');
});
console.log(2);
// 출력:
// 1
// 2
// '부'
// '푸'
console.log(1) 메소드가 호출되어 콜스택에 배치되어 실행됩니다.
SetTimeout이 실행되면 console.log('foo')가 SetTimeout Web Api로 이동되고 0밀리초 후에 Macro-Task Queue로 이동됩니다.
Promise.resolve()가 호출되고 해결되고 .then() 메서드가 마이크로 태스크 대기열로 이동됩니다.
console.log(2) 메소드가 호출되어 콜스택에 배치되어 실행됩니다.
이벤트 루프는 콜 스택이 비어 있음을 확인하고 먼저 Promise 작업인 Micro-Task 큐에서 작업을 가져와 console.log('boo')를 콜 스택에 배치하고 실행합니다.
이벤트 루프는 콜 스택이 비어 있음을 확인한 다음 마이크로 태스크가 비어 있음을 확인하고 매크로 태스크 큐에서 SetTimeout 태스크인 다음 태스크를 가져와 console.log('foo')를 넣습니다. 콜스택에 올려 실행합니다.
예 5의 프로세스 시각화
이벤트 루프에 대한 고급 이해
이벤트 루프 메커니즘이 어떻게 작동하는지에 대한 낮은 수준의 글을 쓰려고 생각하고 있었는데, 그 자체로 게시물이 될 수 있었기 때문에 주제에 대한 소개를 가져오고 주제를 깊이 있게 설명하는 좋은 링크를 첨부하기로 결정했습니다.
이벤트 루프 하위 수준 설명
Node.js가 시작되면 이벤트 루프를 초기화하고, 비동기 API 호출, 타이머 예약 또는 process.nextTick() 호출을 할 수 있는 제공된 입력 스크립트를 처리하거나 REPL에 넣은 다음 이벤트 루프 처리를 시작합니다.
다음 다이어그램은 이벤트 루프의 작업 순서에 대한 간략한 개요를 보여줍니다. (각 상자를 이벤트 루프의 "단계"라고 합니다. 주기를 잘 이해하려면 소개 이미지를 확인하세요.)
이벤트 루프 작업 순서에 대한 단순화된 개요
각 단계에는 실행할 콜백의 FIFO 대기열이 있습니다(구현에 따라 다른 데이터 구조가 있을 수 있으므로 여기서는 주의 깊게 말합니다). 각 단계는 고유한 방식으로 특별하지만 일반적으로 이벤트 루프가 특정 단계에 진입하면 해당 단계에 특정한 작업을 수행한 다음 대기열이 소진되거나 최대 콜백 수에 도달할 때까지 해당 단계의 대기열에서 콜백을 실행합니다. 실행했습니다. 대기열이 소진되거나 콜백 제한에 도달하면 이벤트 루프가 다음 단계로 이동하는 등의 작업이 진행됩니다.
단계 개요
타이머: 이 단계는 setTimeout() 및 setInterval()에 의해 예약된 콜백을 실행합니다.
보류 중인 콜백: 다음 루프 반복으로 연기된 I/O 콜백을 실행합니다.
유휴, 준비: 내부에서만 사용됩니다.
폴링: 새 I/O 이벤트를 검색합니다. I/O 관련 콜백을 실행합니다(닫기 콜백, 타이머에 의해 예약된 콜백 및 setImmediate()를 제외한 거의 모든 것). 적절한 경우 노드가 여기에서 차단됩니다.
확인: 여기에서 setImmediate() 콜백이 호출됩니다.
닫기 콜백: 일부 닫기 콜백. 소켓.on('닫기', ...).
이전 단계가 여기에 어떻게 들어맞나요?
따라서 "콜백 대기열"만 사용한 이전 단계와 "매크로 및 마이크로 대기열"을 사용한 이전 단계는 이벤트 루프 작동 방식에 대한 추상적인 설명이었습니다.
또 하나 언급해야 할 중요한 사항은 이벤트 루프가 매크로 작업 대기열에서 하나의 매크로 작업을 처리한 후 마이크로 작업 대기열을 완전히 처리해야 한다는 것입니다.
1단계: 이벤트 루프는 루프 시간을 현재 실행의 현재 시간으로 업데이트합니다.
2단계: Micro-Queue가 실행됩니다.
3단계: 타이머 단계의 작업이 실행됩니다.
4단계: Micro-Queue에 뭔가가 있는지 확인하고, 뭔가가 있으면 Micro-Queue 전체를 실행합니다.
5단계: 타이머 단계가 빌 때까지 3단계로 돌아갑니다.
6단계: 보류 중인 콜백 단계의 작업이 실행됩니다.
7단계: Micro-Queue에 뭔가가 있는지 확인하고, 뭔가가 있으면 Micro-Queue 전체를 실행합니다.
8단계: 보류 중인 콜백 단계가 비어 있을 때까지 6단계로 돌아갑니다.
그런 다음 유휴… 마이크로 큐… 폴링… 마이크로 큐… 확인… 마이크로 큐… 콜백을 닫고 다시 시작합니다.
그래서 저는 이벤트 루프가 실제로 어떻게 뒤에서 작동하는지에 대한 훌륭한 개요를 제공했습니다. 실제 문서가 이를 잘 설명하고 있기 때문에 여기서 언급하지 않은 누락된 부분이 많이 있습니다. 이에 대한 훌륭한 링크를 제공할 것입니다. 문서 작성에 10~20분 정도 투자하여 이해하시기 바랍니다.
위 내용은 이벤트 루프의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!