자바스크립트 비동기 동작원리

브리·2022년 4월 16일
0

원리가 뭐야

목록 보기
2/4

📌 자바스크립트 동작 구조

우선 자바스크립트가 동작하기 위해서는 자바스크립트 엔진이 필요하다. 자바스크립트 엔진에는 v8, spiderMonkey 등 많지만 대표적인 것은 구글에서 만든 v8 엔진

v8 엔진


엔진은 메모리 할당이 발생하는 메모리 힙과 코드 실행에 따른 스택이 쌓이는 곳인 콜스택으로 구성되어있다.

javascript 를 사용하다보면 setTimeout() 과 같은 API 를 사용하곤 한다. 이러한 API 는 자바스크립트 엔진이 제공하는 요소일까? ✕
이러한 API 들은 Web API라고 해서 웹 브라우저 혹은 node js 와 같은 자바스크립트 런타임에서 제공하는 것이다. 그렇기 때문에 브라우저마다 지원 유무가 다른 것!
( 자바스크립트 런타임: 자바스크립트가 구동되는 환경, 웹브라우저와 node js 와 같은 것들을 모두 포함하는 개념인듯 하다.)

앞서 말했던 것처럼 자바스크립트는 위에서 나온 setTimeout 과 같은 비동기코드 코드를 작성할 수 있지만 처리를 위한 개념을 가지고 있지 않음.
그럼 어떻게 처리? Event Loop & CallBack Queue 의 조합으로!

웹브라우저나 런타임은 웹 API 와 Event Loop & CallBack Queue를 지원해줌.


결과적으로 이러한 동작구조가 탄생하게 된다.
아직은 잘 이해가 되지 않으니 좀 더 자세한 예시를 들면서 이해해보려고 한다.

📌 자바스크립트는 OO 스레드?

Call Stack 은 자바스크립트를 한씩 읽어가며 코드가 순서대로 돌 수 있게 보장해준다. stack 을 사용하기 때문에 후입선출의 방식으로 진행된다.
stack 에 들어있는 하나의 사각형을 stack frame 이라고 하는데 함수가 실행이 되면 pointer 는 stack의 맨 윗부분을 가리키고 있고 함수의 실행이 끝나면 해당 stack frame 에서 제거하게 된다.

만약 스택을 초과한다면?

function foo(){
	foo();
}
foo();

위와 같이 무한루프를 발생시키는 코드를 실행한다면 maximum call stack size 에러가 발생한다.= stack Overflow

이처럼 자바스크립트는 하나의 call stack 을 가지고 코드를 순차적으로 처리하기 때문에 한 번에 하나의 명령만 실행할 수 있다.

답 : 한 번에 여러가지를 할 수 없고 하나씩만 처리할 수 있기 때문에 자바스크립트는 단일 스레드이고 동기식 언어 이다.
자바스크립트는 이러한 특성때문에 무한루프는 발생해도 교착상태(DeadLock)는 발생할 수 없다

📌 그렇다면 자바스크립트는 어떻게 비동기 작업을 수행할까 ?

콜스택만을 사용해서 모든 작업이 실행된다면 많은 기능을 제공하는 사이트의 경우 굉장히 오랜 시간이 걸릴 수 있다. 유저 입장에서 1초만 지연되어도 집중력이 저하되고 신뢰감도 하락한다고 하는데,,,,

이 때 앞서 말한 Event Loop & CallBack Queue 가 해결책이 되어준다.

첫번째 예시

function foo1() {
  console.log("1");
}

function foo2() {
  console.log("2");
}

foo1();
setTimeout(() => {
  console.log("3");
}, 2000);
foo2();

이 코드는 어떻게 실행될까? 1,3,2 ? ❌ 1,2,3 ? ⭕️


두번째 예시

좀 더 직관적으로 이해하기 위해 시작, 끝이라는 단어로 표현해보고자 한다. 사실 내가 더 잘 이해하기 위해서

console.log("시작");
setTimeout(()=>{
	console.log("1초가 지났습니다.");
},0)
console.log("끝");
  1. 콜스택에 console.log("시작") 가 들어가고 실행이 됨 👉🏼 콘솔에 '시작' 이 찍힌다.
  2. setTimeout 이 콜스택이 들어간다. setTimeout 은 비동기함수이기 때문에 Web api 로 콜백함수 timeout()이 들어간다.
  3. 다음 코드인 console.log("끝") 이 콜스택에 들어가고 실행이 된다 👉🏼 콘솔에 '끝' 이 찍힌다.
  4. 웹 API 에서 1초가 지난 후 웹 API 가 제공하는 콜백 큐에 timeout() 함수가 들어간다.
  5. 이벤트 루프가 콜스택이 비었는지를 판별한 후 timeout()함수를 콜스택으로 보낸다.
  6. timeout() 안에 있던 console.log("1초가 지났습니다.")가 콜스택에서 호출되고 실행이 됨 👉🏼 '1초가 지났습니다.' 가 찍힌다.
  7. 모든 함수가 호출되고 콜스택은 비워진다

💡 Event Loop 는 콜백 큐에 있는 콜백함수를 콜 스택으로 보내서 처리하기 위해 콜스택이 비어있는지를 검사한다.

그렇다면 왜 call stack이 비어있어야 할까?

왜 Event Loop는 Call stack이 비어있어야만 Callback Queue의 함수를 처리할까? 밑의 사진은 v8 엔진을 개발한 개발자의 답변이라고 한다. 열심히 해석해봐야지.

CallStack은 누구나 무언가를 push 할 수 있는 데이터 구조가 아닌 여러 함수들을 호출하는 스크립트에서 현재상태의 위치(?)를 추적하는 인터프리터들 위한 term(항 or 매커니즘 과 비슷하게 해석함)을 뜻한다.

만약 정상함수를 잘 실행하고 있다가 event Loop 가 callback queue에 있던 setTimeout 함수를 callstack에 push 했다고 가정하자. 그렇다면 현재 진행중이던 함수를 멈추고 event loop 가 보낸 함수를 실행해야한다. 하지만 이 때 event loop 가 함수를 또 보낸다면..?

callstack 이 비어있을 때만 push 하는 이유는 자바스크립트는 멀티스레드에서 발생할 수 있는 (임계영역 해결을 위한) 동기화과 같은 문제점들을 피하고 싱글스레드언어임을 보장해주기 위함이라고 볼 수 있음~ 정도의 해석을 하였다.

profile
무럭무럭

0개의 댓글