JS | 자바스크립트는 어떻게 동작하는 걸까? 🧐

sol ahn·2021년 11월 21일
0

JavaScript

목록 보기
1/8
post-thumbnail
post-custom-banner

프론트엔드 개발을 공부하면서 숨쉬듯이 자바스크립트를 사용해왔지만, 정작 자바스크립트가 어떤 언어이고 어떻게 동작하는지에 대해서는 잘 알지 못했다. 프론트엔드 개발자로서 기본적인 동작 원리도 모른다는 것은 어불성설이기 때문에 자바스크립트 엔진부터 브라우저 환경, 이벤트 루프, 동기/비동기 등 관련 주제들을 공부해보았다.


자바스크립트 엔진

https://joshua1988.github.io/images/posts/web/translation/how-js-works/js-engine-runtime.png

자바스크립트 엔진은 자바스크립트로 작성된 코드를 읽고 실행하는 인터프리터!

대표적으로 Chrome과 Node.js에서 사용하는 Google V8 엔진이 있음. V8엔진은 싱글 스레드로 동작하며 콜 스택과 메모리 힙을 각각 하나씩 제공함.

ex) 파이어폭스-SpiderMonkey, 사파리-JavaScriptCore, 엣지-Chakra

스크립트나 이벤트 핸들러, 콜백 함수가 실행될 때 활성화됨.

구성 요소

콜 스택(Call Stack)

스택은 함수의 실행 순서를 기억하는 자료 구조. ⇒ 실행하고 있는 프로그램의 현재 위치를 확인할 수 있음.

자바스크립트 엔진은 단 하나의 콜 스택을 사용하기 때문에 함수가 종료되어 콜 스택에서 제거되기 전까지는 어떤 태스크도 실행되지 않음. ⇒ '싱글 스레드(Single Thread)'로 동작함.

콜 스택에는 순차적으로 함수가 push되고 그 함수가 종료되면 pop됨.

자바스크립트 엔진의 콜 스택이 넘치게 되면 Stack-Overflow 에러가 발생할 수 있음! ex) 재귀 함수

자바스크립트 콜 스택 참고사진

메모리 힙(Memory Heap)

객체가 저장되는 메모리 공간으로 실행 컨텍스트는 힙에 저장된 객체를 참조함.

객체는 크기가 정해져있지 않기 때문에 할당해야 할 메모리 공간의 크기를 런타임에 결정해야 함. ⇒ 동적 할당

메모리 힙은 구조화되어 있지 않으므로 데이터들이 여기저기 저장되어 있음.

브라우저 환경

비동기 처리에서 소스코드의 평가와 실행을 제외한 모든 처리는 자바스크립트 엔진을 구동하는 환경인 브라우저 or Node.js가 담당함.

Web APIs

브라우저에서 제공하는 API

DOM API, Ajax, 타이머 함수 등의 메서드 지원

console.log('hi');

setTimeout(function cb() {
	console.log('hey');
}, 0);

console.log('yeah');

// hi
// yeah
// hey

setTimeout 함수는 얼마 후 동작하는 최소 시간을 보장함. 따라서 만약 0초의 타이머가 설정되어있어도 콜 스택이 비어있지 않으면 콜백이 바로 실행되지 않고, 완전히 콜 스택이 비어야 실행됨.

태스크 큐(Task Queue) or 콜백 큐(Callback Queue) or 이벤트 큐(Event Queue)

비동기 처리의 콜백 함수나 이벤트 핸들러가 일시적으로 보관되는 영역

태스크 큐에 들어온 태스크들은 콜 스택이 비어있을 때 들어온 순서대로 실행됨.

마이크로 태스크 큐(Micro Task Queue)

Promise or MutationObserver에 등록된 콜백 함수가 일시적으로 보관되는 영역

마이크로 태스크 큐가 완전히 빌 때까지 콜백 함수를 실행함.

MutationObserver: DOM의 변경사항을 감시하는 빌트인 객체

이벤트 루프(Event Loop)

브라우저에 내장되어 있는 기능 중 하나로, 자바스크립트의 '동시성'을 지원함.

콜 스택에 현재 실행 중인 함수가 있는지, 태스크 큐에 대기 중인 함수가 있는지 반복 확인함.

콜 스택이 비어있고 태스크 큐에 대기 중인 함수가 있다면 이벤트 루프는 순차적으로 태스크 큐에 대기 중인 함수를 콜 스택으로 옮김. ⇒ 비동기 처리 방식

  • 이벤트 루프 동작 예시
const foo = () => console.log("First");
const bar = () => setTimeout(() => console.log("Second"), 500);
const baz = () => console.log("Third");

bar();
foo();
baz();

이벤트 루프 동작 시각화 자료1

콜 스택에서 시간이 오래 걸리는 함수를 실행하게 되면 이벤트 루프가 계속 머물러야하기 때문에 브라우저가 멈추게 됨. 마찬가지로 렌더링도 콜백 함수와 같기 때문에 스택에 함수가 있으면 화면이 렌더링되지 못함.

⇒ 함수는 최대한 간단하게 작성하고, 시간이 오래 걸리는 함수는 작게 쪼개서 작성하는 것이 좋음!

💡 태스크 큐마이크로 태스크 큐의 차이점? 태스크 큐는 태스크가 하나씩 콜 스택으로 옮겨지기 때문에 이벤트 루프가 계속 돌아가지만, 마이크로 태스크 큐는 태스크가 모조리 실행될 때까지 이벤트 루프가 머물러 있기 때문에 화면이 멈추게 됨.

이벤트 루프 동작 시각화 자료2

Synchronous VS Asynchronous / Blocking VS Non-Blocking

Synchronous VS Asynchronous

💡 호출된 함수의 작업 여부를 호출한 함수가 신경을 쓰는가? ⇒ 동시성

Synchronous: 호출한 함수는 호출된 함수가 실행되는 중에 기다리면서 현재 상태가 어떤지 계속 확인함.

Asynchronous: 호출된 함수의 수행 작업 여부를 그 함수가 혼자 직접 신경쓰면서 처리함. ⇒ 비동기 콜백

Blocking VS Non-Blocking

💡 호출된 함수가 바로 리턴 되는가? ⇒ 제어권

Blocking: 호출된 함수에서 할 일을 다 마친 다음 호출한 함수에게 제어권을 넘겨줌.

Non-Blocking: 호출된 함수에서 일을 시작할 때 바로 호출한 함수에게 제어권을 넘겨줌.

Synchronous, Asynchronous, Blocking, Non-Blocking 조합 도표

성능과 자원의 효율적인 운용을 생각한다면 'Async-NonBlocking' 이 최적의 모델!

Ref

[유튜브] 얄코 비동기 프로그래밍
[유튜브] What the heck is the event loop anyway?
[도서] 이웅모, ⌜모던 자바스크립트 Deep Dive⌟, 위키북스, 2020
[블로그] 자바스크립트의 동작원리: 엔진, 런타임, 호출 스택
[블로그] 자바스크립트 런타임
[블로그] JavaScript 동작원리를 살펴봅시다
[블로그] In-Depth Introduction to Call Stack in JavaScript.
[블로그] ⭐️🎀 JavaScript Visualized: Promises & Async/Await
[사이트] http://latentflip.com
[블로그] Blocking-NonBlocking-Synchronous-Asynchronous
[블로그] blocking and synchronous

profile
아는 만큼 재밌는 개발자 🤓
post-custom-banner

0개의 댓글