0w0

자바스크립트, 비동기 그리고 이벤트 루프

동기, 목표

비동기와 이벤트루프를 조사해서 정리하자!

의문 전개 과정

사전지식

JS

JavaScript (JS)는 가벼운, 인터프리터 혹은 just-in-time 컴파일 프로그래밍 언어로, 일급 함수를 지원합니다. 웹 페이지를 위한 스크립트 언어로 잘 알려져 있지만, Node.js, Apache CouchDB, Adobe Acrobat처럼 많은 비 브라우저 환경에서도 사용하고 있습니다. JavaScript는 프로토타입 기반, 다중 패러다임, 단일 스레드, 동적 언어로, 객체지향형, 명령형, 선언형(함수형 프로그래밍 등) 스타일을 지원합니다.

mdn


JavaScript (줄여서 JS)는 일급 함수를 사용하는 가벼운 객체 지향 인터프리터 언어이며 웹페이지의 스크립트 언어로 잘 알려져 있지만, 브라우저가 아닌 환경에서도 많이 사용된다. 프로토타입 기반, 다중 패러다임 스크립트 언어이며, 동적이고 명령어, 객체 지향, 함수 프로그래밍 스타일을 지원한다.

자바스크립트는 클라이언트 측 웹(브라우저)에서 실행 되고, 웹 페이지가 이벤트 발생 시 어떻게 작동하는 지 디자인 / 프로그래밍할 수 있다. 자바스크립트는 쉽게 배울 수 있고 강력한 스크립트 언어로 웹 페이지 동작을 제어하는 데 널리 사용된다.

mdn


JavaScript는 싱글스레드로 논블로킹 비동기처리, 병렬처리 가능한 언어이며, 콜백, 이벤트 루프, 콜백 큐 같은 API를 가지고 있다.

qiita

JS 런타임

JS 런타임은 힙 메모리가 메모리 얼록, 콜 스택은 스택 프레임 관리를 한다. JavaScript runtime Memory Heap and Call Stack

그리고 흔히 쓰는 V8 엔진에는 예상 외로 setTimeout, DOM, HTTP request없다.

이 기능은 브라우저 WebAPIs를 사용한다.

콜 스택

현재 프로그램이 어떤 상황에 처해 있는지 기록한 자료 구조이다.

JS는 싱글스레드 언어이므로 1개의 스레드만 동작해서 1개의 콜 스택을 가지고 있다.

즉, 한 번에 한 놈. 턴의 법칙이다

function multiply(a, b) {
  return a * b;
}

function square(n) {
  return multiply(n, n);
}

function printSquare(n) {
  const squared = square(n);
  console.log(squared);
}

printSquare(4);

이 코드의 작동 방식을 영상에서 확인하자

블록킹

Node.js에서 블록킹 의미를 보면

Node.js 프로세스에서 추가 JS 실행이 JS 이외 조작이 완료될 때까지 기다리는 것으로, 이벤트 루프가 블록킹된 조작을 하는 동안 JS 실행을 계속 하기위해 일어납니다.

Node.js에서는 I/O 같이 비 JS 조작을 기다리지 않고, CPU에 부하때문에 퍼포먼스를 저하시키는 JS는 블록킹이라 하지 않는다.

libuv를 사용하는 Node.js 표준 라이브러리의 동기 메서드가 가장 일반적으로 사용하는 블록킹 조작이다.

네이티브 모듈도 블록킹 메서드를 가지고 있을 때가 있다.

Node.js 표준 라이브러리의 모든 I/O 메서드는 비동기 버전을 제공하고 이를 논블록킹으로 콜백 함수를 처리한다.

몇 몇 메서드는 Sync로 끝나는 이름을 갖은 블로킹 상대가 있다.

즉, JavaScript는 I/O 처리 같이 시간이 걸리는 처리를 비동기 함수로 처리하므로 "그 I/O처리가 끝날 때까지 JavaScript 실행되지 않는다(block 된다)" 상황을 회피하는 것

여담: 그런데 Node.js는 논 블로킹이라는데 그럼 이거 어떻게 되는거지

Render Queue

콜 스택 처리할 것이 있을 때 브라우저 render할 수 없습니다.

콜 스택이 비워질 떄까지 rendering 됩니다.

Render Queue, 콜 스택이 비워지면, Task Queue에서 Call Stack으로 push 합니다.

병행성

브라우저에서 JS 처리는 이런 식으로 생겼다.

js runtime in browser

우선 순위는 Call Stack > Render Queue > Task Queue

  1. Call Stack 비워지면 Render Queue에서 처리가 하나씩 나와 렌더링
  2. Call Stack, Render Queue가 비워지면 Task QuNEWeue에서 하나씩 끄집어내 Call Stack에 push

이벤트 루프

이벤트 루프(event loop) 정의는 아주 간단합니다. 이벤트 루프는 태스크가 들어오길 기다렸다가 태스크가 들어오면 이를 처리하고, 처리할 태스크가 없는 경우엔 잠드는, 끊임없이 돌아가는 자바스크립트 내 루프입니다

비동기처리

이벤트 루프는 비동기처리를 위한 아이디어

promise

async/await

그런데 어떻게 싱글 스레드인데 여러 가지 처리가 가능하지...?

이벤트 루프

the_javascript_runtime_environment_example

위는 mdn에서 제공하는 자바스크립트 런타임 환경을 시각화 한 것이다.

에서 스택, 큐를 기억해두자.

mdn에서 제공하는 이벤트 루프의 추상코드를 보자.

while (queue.waitForMessage()) {
  queue.processNextMessage();
}

queue.waitForMessage() 함수는 현재 처리할 수 있는 메시지가 존재하지 않으면 새로운 메시지가 도착할 때까지 동기적으로 대기합니다. - mdn

그럼 브라우저 API를 쓰는 브라우저랑 Node는 행동이 같나?

브라우저

event loop in browser

Node.js

event loop in node.js

읽을거리