주의! Node.js 를 처음 접해보는 초보 개발자가 정리하는 글이므로 부족한 점이 많을 수 있습니다.
이벤트 기반
이벤트 기반(event-driven)이란 이벤트가 발생할 때 미리 지정해둔 작업을 수행하는 방식을 의미한다. 이벤트로는 클릭이나 네트워크 요청 등이 있을 수 있다.
이벤트 기반 시스템에서는 특정 이벤트가 발생할 때 무엇을 할지 미리 등록해 두어야 한다. 이를 이벤트 리스너(event-listener)에 콜백(callback) 함수를 등록한다고 표현한다. 버튼을 클릭할 때 경고창을 띄우도록 설정하는 것을 예로 들자면 클릭 이벤트 리스너에 경고창을 띄우는 콜백 함수를 등록해두면 클릭 이벤트가 발생할 때마다 콜백 함수가 실행되어 경고창이 발생되는 것이다.
노드도 이벤트 기반 방식으로 동작하므로, 이벤트가 발생하면 이벤트 리스너에 등록해둔 콜백 함수를 호출한다. 발생한 이벤트가 없거나 발생했던 이벤트를 모두 처리하면, 노드는 다음 이벤트가 발생할 때가지 대기한다.
이벤트 기반 모델에서는 이벤트 루프(event-loop)라는 개념이 등장한다. 여러 이벤트가 동시에 발생했을 때 어떤 순서로 콜백 함수를 호출할지를 이벤트 루프가 판단한다.
이벤트 루프? (event-loop)
이벤트 발생 시 호출할 콜백 함수들을 관리하고, 호출된 콜백 함수의 실행 순서를 결정하는 역할을 담당한다. 노드가 종료될 때까지 이벤트 처리를 위한 작업을 반복하므로 루프(loop)라고 부른다.
백그라운드? (background)
setTimeout 같은 타이머나 이벤트 리스너들이 대기하는 곳이다. 자바스크립트가 아닌 다른 언어로 작성된 프로그램이라고 봐도 된다. 여러 작업이 동시에 실행될 수가 있다.
태스크 큐? (task-queue)
이벤트 발생 후, 백그라운드에서는 테스크 큐로 타이머나 이벤트 리스너의 콜백 함수를 보낸다. 정해진 순서대로 콜백들이 줄을 서 있으므로 콜백 큐라고도 부른다. 콜백들은 보통 완료된 순서대로 있지만 특수한 경우 순서가 바뀌기도 한다.
노드는 자바스크립트 코드의 맨 위부터 한 줄씩 실행한다. 함수 호출 부분을 발견했다면 호출한 함수를 호출 스택(call-stack)에 넣는다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
function one() {
second();
console.log("A");
}
function two() {
three();
console.log("B");
}
function three() {
console.log("C");
}
one();
|
cs |
위 코드는 one(); 함수가 가장 먼저 호출되고 two(); 함수를 호출하고 마지막으로 three(); 함수를 호출된다. 실행은 호출된 순서와 반대로 실행이 완료된다. 따라서 콘솔에는 C, B, A 순서로 찍히게 된다.
블로킹과 논 블로킹 I/O
이벤트 루프를 잘 활용하면 오래 걸리는 작업을 효율적으로 처리할 수 있다. 작업에는 두 가지 종류가 있는데, 동시에 실행될 수 있는 작업과 동시에 실행될 수 없는 작업이다.
저 위에서 작성한 코드와 같이 기본적으로 작성하는 자바스크립트 코드는 동시에 실행될 수 없다. 하지만 자바스크립트상에서 돌아가는 것이 아닌 I/O 작업 같은 것은 동시에 처리될 수 있다.
I/O는 입력(Input)/출력(Output)을 의미한다. 파일 시스템 접근이나 네트워크를 통한 요청 같은 작업이 I/O의 일종이다. 이러한 작업을 할 때 노드는 논 블로킹 방식을 처리한는 방법을 제공한다. 논 블로킹이란 이전 작업이 완료될 때까지 대기하지 않고 다음 작업을 수행함을 뜻한다. 반대로 블로킹은 이전 작업이 끝나야만 다음 작업을 수행하는 것을 의미한다.
여기서 든 의문이 있었다.
- 논 블로킹/블로킹과 비동기/동기는 동일한건가?
해당 의문은 velog.io/@codemcd/Sync-VS-Async-Blocking-VS-Non-Blocking-sak6d01fhx 여기서 해소되었다.
결론만 인용을 하자면 아래와 같다.
이는 서로 관점이 다르다. 블록킹/논블록킹은 직접 제어할 수 없는 대상을 처리하는 방법에 따라 나눈다. 직접 제어할 수 없는 대상은 대표적으로 IO, 멀티쓰레드 동기화가 있다.
- Synchronous VS Asynchronous
- 두 가지 이상의 대상(메서드, 작업, 처리 등)과 이를 처리하는 시간으로 구분한다.
- Synchronous: 호출된 함수의 리턴하는 시간과 결과를 반환하는 시간이 일치하는 경우
- Asynchronous: 호출된 함수의 리턴하는 시간과 결과를 반환하는 시간이 일치하지 않는 경우
- Blocking VS Non-Blocking
- 호출되는 대상이 직접 제어할 수 없는 경우 이를 구분할 수 있다.
- Blocking: 직접 제어할 수 없는 대상의 작업이 끝날 때까지 기다려야 하는 경우
- Non-Blocking: 직접 제어할 수 없는 대상의 작업이 완료되기 전에 제어권을 넘겨주는 경우
블로킹과 논블로킹의 동작 차이
위 첫번째의 사진을 보면 순서의 중요성을 알 수 있다. 처리하는 데 1초가 걸리는 작업들이라면 블로킹 방식에서는 모든 작업이 완료 되기까지 3초가 소요되게 된다. 해당 작업을 논 블로킹 방식으로 작성하면 모든 작업이 완료 되기까지 3초보다는 훨씬 빨리 끝날것이다.
글쓴이는 book.naver.com/bookdb/book_detail.nhn?bid=16418778 이 책을 참고하여 게시글을 작성하고 있습니다.