자바스크립트, 비동기 그리고 이벤트 루프
동기, 목표
비동기와 이벤트루프를 조사해서 정리하자!
의문 전개 과정
- 자바스크립트에는 이벤트 루프라는 것이 있는데 이건 뭐지?
- 이벤트 루프는 비동기 처리하는 것이라는데 어떤 연관성이 있지?
- 애초에 비동기처리는 뭐지?
- 그런데 자바스크립트는 싱글 스레드라 들었는데 어떻게 비동기 처리하지?
- 비동기는 브라우저/Node.js 작동이 같나?
사전지식
JS
JavaScript (JS)는 가벼운, 인터프리터 혹은 just-in-time 컴파일 프로그래밍 언어로, 일급 함수를 지원합니다. 웹 페이지를 위한 스크립트 언어로 잘 알려져 있지만, Node.js, Apache CouchDB, Adobe Acrobat처럼 많은 비 브라우저 환경에서도 사용하고 있습니다. JavaScript는 프로토타입 기반, 다중 패러다임, 단일 스레드, 동적 언어로, 객체지향형, 명령형, 선언형(함수형 프로그래밍 등) 스타일을 지원합니다.
JavaScript (줄여서 JS)는 일급 함수를 사용하는 가벼운 객체 지향 인터프리터 언어이며 웹페이지의 스크립트 언어로 잘 알려져 있지만, 브라우저가 아닌 환경에서도 많이 사용된다. 프로토타입 기반, 다중 패러다임 스크립트 언어이며, 동적이고 명령어, 객체 지향, 함수 프로그래밍 스타일을 지원한다.
자바스크립트는 클라이언트 측 웹(브라우저)에서 실행 되고, 웹 페이지가 이벤트 발생 시 어떻게 작동하는 지 디자인 / 프로그래밍할 수 있다. 자바스크립트는 쉽게 배울 수 있고 강력한 스크립트 언어로 웹 페이지 동작을 제어하는 데 널리 사용된다.
JavaScript는 싱글스레드로 논블로킹 비동기처리, 병렬처리 가능한 언어이며, 콜백, 이벤트 루프, 콜백 큐 같은 API를 가지고 있다.
JS 런타임
JS 런타임은 힙 메모리가 메모리 얼록, 콜 스택은 스택 프레임 관리를 한다.
그리고 흔히 쓰는 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 프로세스에서 추가 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 처리는 이런 식으로 생겼다.
우선 순위는 Call Stack > Render Queue > Task Queue
Call Stack
비워지면Render Queue
에서 처리가 하나씩 나와 렌더링Call Stack
,Render Queue
가 비워지면Task QuNEWeue
에서 하나씩 끄집어내Call Stack
에 push
이벤트 루프
비동기처리
이벤트 루프는 비동기처리를 위한 아이디어
promise
async/await
그런데 어떻게 싱글 스레드인데 여러 가지 처리가 가능하지...?
이벤트 루프
위는 mdn에서 제공하는 자바스크립트 런타임 환경을 시각화 한 것이다.
- Stack(콜 스택)
- Queue(메세지 큐)
- Heap(객체 두는곳)
에서 스택, 큐를 기억해두자.
mdn에서 제공하는 이벤트 루프의 추상코드를 보자.
while (queue.waitForMessage()) {
queue.processNextMessage();
}
queue.waitForMessage() 함수는 현재 처리할 수 있는 메시지가 존재하지 않으면 새로운 메시지가 도착할 때까지 동기적으로 대기합니다. - mdn
그럼 브라우저 API를 쓰는 브라우저랑 Node는 행동이 같나?
브라우저
Node.js
읽을거리
- https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=240603144
- https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=246391275
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop
- https://www.geeksforgeeks.org/difference-between-promise-and-async-await-in-node-js/
- https://www.freecodecamp.org/news/async-await-and-promises/
- https://stackoverflow.com/questions/53057110/difference-of-using-async-await-vs-promises
- https://zenn.dev/estra/books/js-async-promise-chain-event-loop/viewer
- https://zenn.dev/mizchi/articles/understanding-promise-by-ts-eventloop
- https://dev.to/lydiahallie/javascript-visualized-event-loop-3dif
- https://dev.to/lydiahallie/javascript-visualized-promises-async-await-5gke
- https://dev.to/lydiahallie/javascript-visualized-the-javascript-engine-4cdf
- https://developer.mozilla.org/ko/docs/Web/JavaScript/EventLoop
- https://zenn.dev/estra/articles/js-async-programming-roadmap
- https://tc39.es/ecma262/multipage/control-abstraction-objects.html#sec-promise-objects
- https://azu.github.io/promises-book/
- https://nodejs.org/
- https://nodejs.dev/learn/the-nodejs-event-loop
- https://dev.to/jasmin/difference-between-the-event-loop-in-browser-and-node-js-1113
- http://latentflip.com/loupe/?code=JC5vbignYnV0dG9uJywgJ2NsaWNrJywgZnVuY3Rpb24gb25DbGljaygpIHsKICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gdGltZXIoKSB7CiAgICAgICAgY29uc29sZS5sb2coJ1lvdSBjbGlja2VkIHRoZSBidXR0b24hJyk7ICAgIAogICAgfSwgMjAwMCk7Cn0pOwoKY29uc29sZS5sb2coIkhpISIpOwoKc2V0VGltZW91dChmdW5jdGlvbiB0aW1lb3V0KCkgewogICAgY29uc29sZS5sb2coIkNsaWNrIHRoZSBidXR0b24hIik7Cn0sIDUwMDApOwoKY29uc29sZS5sb2coIldlbGNvbWUgdG8gbG91cGUuIik7%21%21%21PGJ1dHRvbj5DbGljayBtZSE8L2J1dHRvbj4%3D
- https://www.youtube.com/watch?v=8aGhZQkoFbQ&t=2s
- https://www.jsv9000.app/
- https://html.spec.whatwg.org/multipage/webappapis.html#task-queue
- https://qiita.com/l1lhu1hu1/items/57dcc7cb867eee951f36
- https://zenn.dev/qnighy/articles/345aa9cae02d9d
- https://geekflare.com/javascript-event-loops/
- https://dev.to/bbarbour/if-javascript-is-single-threaded-how-is-it-asynchronous-56gd
- https://developer.mozilla.org/ko/docs/Web/JavaScript/Memory_Management