자바스크립트 동작원리 (엔진, 런타임, 이벤트 루프)

JavaScript는 싱글스레드?

Javascript는 싱글스레드로 동작하는 언어입니다. 메인 스레드, 하나의 스레드로 구성되어 있기 때문입니다.

싱글스레드는 한번에 하나의 작업만 수행할 수 있습니다.다른 작업이 중간에 끼어들 수도 없고, 기존에 수행하던 작업이 끝나야만 그 다음 작업을 수행할 수 있습니다.

싱글스레드인데 어떻게 비동기적인 실행이 가능한것일까?

이제 부터 알아보자!!

자바스크립트 엔진

위의 그림처럼 Javascript의 엔진은 메모리 힙(memory heap)과 콜스택(call stack)으로 구성되어 있습니다.

  • memory heap: 메모리 할당이 일어나는 곳
  • call stack: 코드가 호출되면서, 스택으로 쌓이는 곳

하나의 메인스레드에서 호출되는 함수들이 콜스택에 쌓이고, 이 함수들은 LIFO(Last In First Out)방식으로 실행됩니다. 호출 스택이 하나이므로 자바스크립트가 단일 스레드인 것은 맞습니다.

단일 스레드가 맞네.. 그러면 어떻게 비동기적인 처리가 가능한것일까요??

동시성을 보장하는 비동기, 논블로킹 작업들은 Javascript 엔진을 구동하는 런타임(Runtime) 환경에서 담당합니다.

자바스크립트 런타임

자바스크립트 엔진 밖에서도 자바스크립트에 관여하는 요소(Wep API, Task Queue, Event Loop)들이 있습니다.런타임은 특정 언어로 만든 프로그램들을 실행할 수 있는 환경이고, Node.js나 크롬등의 브라우저들은 자바스크립트가 구동되는 환경이기 때문에, 이를 자바스크립트 런타임이라고 합니다.

  • Web APIs : 브라우저에서 자체 지원하는 api입니다. Web api는 이벤트리스너, Ajax, setTimeout 등의 비동기 작업들을 수행할 수 있도록 api를 지원함
  • Callback queue : 콜백 함수들이 대기하는 곳(FIFO 선입선출)
  • Event Loop : 이벤트 발생 시 호출되는 콜백 함수들을 콜백 큐에 전달하고 Call Stack이 빈 상태가 되면, 콜백 큐에 담겨있는 콜백 함수들을 콜스택에 넘겨줌 (이러한 반복적인 행동을 틱(tick) 이라 부릅니다.)

이번에는 아래의 코드가 어떻게 비동기로 작동하는지 자세히 알아봅시다!

console.log("시작");

setTimeout(function(){
    console.log("3초후 실행");
}, 3000);

console.log("끝")
  1. 먼저 전역 컨텍스트 main() 함수가 Call Stack에 쌓이고 console.log(“시작”) 이 Call Stack에 쌓인다. “시작”이 콘솔에 찍힌다.
  2. console.log(“시작”) 이 리턴되며 Call Stack에서 제거된다.
  3. setTimeout함수가 실행되면서 Call Stack에 setTimeout함수가 들어간다.
  4. setTimeout함수는 자바스크립트 엔진이 처리하지않고 Web API가 처리하므로 Callback함수를 전달하고, setTimeout작업을 요청한다.
  5. Call Stack에서는 setTimeout작업이 제거된다.
  6. console.log(“끝”) 이 호출되어 Call Stack에 쌓인다. “끝”이 콘솔에 찍힌다.
  7. console.log(“끝”) 이 리턴되며 Call Stack에서 제거된다.
  8. main() 함수가 리턴되며 Call Stack에서 제거된다.
  9. Web API는 setTimeout 작업을 실행한다. 3초를 센 후 Task Queue로 Callback 함수를 보낸다.
  10. Event Loop는 Call Stack이 비어있으면 Task Queue에서 함수를 하나씩 꺼내 Call Stack에 넣고 실행한다.
  11. console.log(“3초후 실행”) 이 호출되고 Call Stack에 쌓인다. “3초후 실행”이 콘솔에 찍힌다.
  12. console.log(“3초 후 실행”) 이 리턴되고 Call Stack에서 제거된다. Event Loop는 Task Queue에 콜백 함수가 들어올 때까지 계속 대기한다.

예를 들면 이와 같은 코드라면?

console.log("시작");

setTimeout(function(){
    console.log("0초후 실행");
}, 0);

console.log("끝");

결과

시작
끝
0초후 실행

이렇게 됩니다.setTimeOut 이라면 WebAPI로 이동을 시킨후, 테스크큐에 보낸후 비었을때 스택으로 올려보내기 때문입니다.! (스택이 비었다는것은 이미 console.log("끝")이 실행되었다는 것)

이를 토대로 알게된 내용

  • 10초걸리는 (오래 걸리는) 어려운 연산코드를 자바스크립트로 시키면 안됩니다.

→ 이유는? 만약에 버튼을 눌러서 모달창을 띄우는 코드라면, Web API로 이동하게 되고 테스크큐를 거쳐 스택으로 이동해야하는데, 스택이 비어져있을때만 실행이 가능합니다. 그런데 스택에는 10초가 걸리는 연산작업중이기 때문에 모달창을 띄울수가 없습니다. (그래서 버튼을 눌러도 아무반응이 없음)

  • 자바스크립트는 동기적인 언어이고, 가끔 비동기적인 처리(ajax, setTimeout,이벤트 리스너 등)도 가능합니다.

그러면 비동기 작업은 왜 필요한가요?

→ 화면에서 서버로 데이터를 요청했을 때 서버가 언제 그 요청에 대한 응답을 할지도 모르는 상태에서 다른 코드를 실행 안하고 기다릴 수는 없기 때문입니다.

좋은 웹페이지 즐겨찾기