[JS] 자바스크립트 동작원리

GyungHo Go·2023년 1월 2일
0

자바스크립트는 동기 방식의 싱글스레드 기반 언어이다. 즉, 한번에 하나의 작업 또는 한줄 씩 처리를 할수 가 있다. 함수를 실행하면 함수 호출이 스택에 순차적으로 쌓이고, 스택의 맨 위에서 부터 하나의 함수가 호출되어 실행된다. 하지만 이러한 자바스크립트는 비동기 처리가 가능하다.

그렇다면 브라우저에서 자바스크립트가 어떻게 동작하고, 어떻게 비동기 처리가 되는지 알아보려고 한다.

자바스크립트

싱글 스레드(Single Thread)

자바스크립트는 싱글 스레드 기반 언어이다.
싱글 스레드는 하나의 힙 영역과, 콜 스택을 가진다. 하나의 콜 스택을 가진다는 것은 한번에 하나의 일 밖에 하지 못한다는 의미이다. 어떤 버튼을 클릭했을때, 이 작업이 완료되기 전까지 다른 동작은 할 수가 없게된다.

자바스크립트 엔진


자바스크립트 엔진은 다음과 같은 구성요소로 구성되어있다.
구글의 V8은 자바스크립트 엔진의 대표적인 예이다. Chrome과 node.js에서 사용한다.

자바스크립트는 단일 스레드(single thread)언어인데, 이는 Call Stack이 하나라는 의미이다.

  • Memory Heap : 변수나 객체의 메모리 할당이 일어나는 곳
  • Call Stack : 코드 실행에 따라 호출 스택이 쌓이는 곳

Call Stack

자바스크립트는 싱글스레드 기반 언어이기 때문에 한번에 하나의 작업을 처리한다. 함수가 실행이 되면 Call Stack에 순차적으로 쌓이고, 스택의 맨 위에서 부터 함수가 하나씩 실행이 된다.

콜스택은 기본적으로 자바스크립트를 한 줄씩 순서대로 읽게되는 데이터 구조이다. 후입선출(LIFO, Last-In-First-Out)의 구조를 갖는다.

function first() {
  second();
  console.log('first');
}
function second() {
  third();
  console.log('second');
}
function third() {
  console.log('third');
}

first();

main() 함수는 처음 실행시 전역 컨텍스트(함수가 호출 되었을 때 생성되는 환경)이다. 함수의 실행이 완료되면 스택에서 하나씩 지워진다. main함수까지 실행이 완료되면 스택이 비워진다. 콘솔로 확인해 보면 다음과 같다.

💡 자바스크립트 런타임

그림과 같이 자바스크립트 엔진이 있고, Event LoopCallback Queue, 그리고 Web APIs가 있다.

런타임은 언어로 만든 프로그램들을 실행할 수 있는 환경을 말한다. 이벤트 루프와 콜백 큐는 자바스크립트 엔진에 속하지 않는다. 이를 둘러싼 환경이라고 할 수 있다.
이는 자바스크립트 엔진을 구동하는 런타임 환경(브라우저, node.js)이 담당한다.

Node.js나 크롬등의 브라우저들은 자바스크립트가 구동되는 환경이기 때문에 이를 자바스크립트 런타임이라고 한다.

자바스크립트는 이러한 런타임 환경 제공하는 것을 가지고 비동기 요청을 처리한다.

👉🏻 런타임 환경이 제공하는 것

Web Api

브라우저에서 제공되는 API이다. 자바스크립트 엔진에서 정의되지 않았던 setTimeout이나 AJAX(HTTP 요청), DOM 이벤트 등 메소드를 지원한다.

Call Stack에서 실행된 비동기 함수는 Web API를 호출하고, Web API는 콜백함수를 Callback Queue에 넣는다.

Task Queue

이벤트 발생 후 호출 되어야 할 콜백 함수들이 기다리는 공간이다. 이벤트 루프가 정한 순서대로 줄을 서 있으므로 콜백 큐(Callback Queue) 라고도 한다.

  • Queue(큐): 자료 구조 중 하나로 선입선출(FIFO, First In First Out)의 룰을 따른다.

Event Loop

이벤트 루프는 콜 스택과 콜백 큐의 상태를 관찰하는 역할을 한다. 콜 스택이 비어있으면 콜백 큐에 대기 중인 첫번째 함수를 순차적으로 스택에 쌓는다. 이러한 반복적인 행동을 틱(tick) 이라고 한다.

setTimeout()같은 비동기 처리가 가능함에도 불구하고, 자바스크립트 자체에는 비동기 코드를 처리하기 위한 개념을 갖고 있지 않다. 하지만 Event Loop, Callback Queue로 가능하게 된다. 다음과 같은 구조로 자바스크립트는 비동기처리가 가능하다.

자바스크립트 비동기 작업

Call Stack에서 처리하는데 엄청난 시간이 걸리는 함수 호출이 있으면 어떻게 될까? 이럴 경우 스택에 실행할 함수가 있는 동안 브라우저는 다른 작업을 수행 할 수 없다. 즉 브라우저가 차단된다. 그리고 브라우저가 스택에서 너무 많은 작업을 처리하기 시작하면 응답을 하지 않을 수 도 있다.

UI를 차단하지 않고 브라우저가 응답하지 않게 만들지 않고 무거운 코드를 실행 하려면 해결책은 비동기처리이다.

다음과 같은 코드가 있다고 하자.

function foo() {
  console.log('1');
}
function bar() {
  console.log('2');
}

foo();
setTimeout(function () {
  console.log('3');
}, 1000);
bar();

어떤 순서대로 실행이 될까? 1,3,2라고 예상하겠지만 틀렸다.
정답은 1,2,3으로 출력이 된다.

분명 하나의 스택을 사용하기 때문에 순서대로 처리가 된다면 1,3,2일텐데 어떻게 이런 결과가 나온것일까?

이것을 알기 위해서는 Event loopCallback Queue의 동작 방식을 알아야 한다.

  • 우선 foo() 라는 함수가 Call Stack에 쌓이게 된다. 그 다음 foo() 함수 안에 있는 console.log('1')가 스택에 쌓이게 된다.
  • 콘솔창에 '1'이 출력된다.
  • foo() 함수는 종료되어 스택에서 사라지게되고, 그 다음 setTimeout()이 스택으로 들어온다.
  • setTimeout, Ajax, Dom이벤트 관련 함수들은 Web API에서 처리하도록 보낸다. 그리고 그 다음 실행 함수인 bar() 함수를 불러온다. 그리고 bar() 함수 안에있는 console.log('2')가 스택에 쌓이게 된다.
  • 그리고 콘솔창에 '2'가 출력된다. 그리고 bar() 함수는 스택에서 사라진다.
  • setTimeout() 함수는 1초로 설정해 두었으니 1초간은 Web API에서 처리가 된다. 그리고 1초가 지난 후에 setTimeout()의 콜백함수를 Queue로 보내게 된다.
  • 중요한 점은 스택에서 bar() 함수를 처리하고 있고, Web API에서는 setTimeout()을 1초동안 돌리고 있게된다.
  • 여기서 Event Loop가 등장한다. 이벤트 루프는 큐에 콜백 함수를 스택으로 보내서 처리하기 위해 콜스택이 비어있는지 확인을 한다. 이때 콜스택이 비어 있다면 큐에 있는 함수를 스택으로 보내서 처리 하게 된다.
  • Call Stack에 있던 console.log('3')를 콘솔에 출력하는 것으로 프로그램을 종료한다.

🤔 만약 setTimeout()의 시간을 0으로 하면 어떻게 될까?

console.log('a');
setTimeout(function() {
  console.log('b');
}, 0);
console.log('c');


이는 0초 후에 실행을 시킨다는 의미이다. 즉시 실행될 것 같지만 실제로는 실행되지 않는다. 그 이유는 콜스택이 비어있지 않기 때문이다. setTimeout같은 비동기함수는 반드시 Web api를 거쳐서 태스크 큐에 대기했다가 콜스택이 비었을때 비로소 이동해서 실행이 되기 때문이다.

출처

profile
기록하는 습관

0개의 댓글

관련 채용 정보