💡 자바스크립트의 언어적 특징과 동작 방식에 대해 개인적으로 정리한 내용을 기록합니다. 잘못된 부분에 대한 지적이나 피드백 감사드립니다 :)
: 소스코드를 기계어로 변환하는 과정(컴파일)없이
런타임에 한 줄씩 바이트코드로 변환해가며 명령어를 실행한다
JIT 컴파일러
를 내장하고 있어 실행속도가 매우 빨라졌다.JIT 컴파일러
: 기본적으로 인터프리터 방식으로 동작하지만, 자주 반복되는 코드들은 최적화를 위해 엔진에서 미리 컴파일해둔다JITC
의 장점은💡 - 그럼 무조건 JITC가 좋은거네?
👉 Nope
JITC
의 최적화는 자주 사용하는 코드에 대한 최적화를 진행하기 때문에, 런타임에 동적으로 변수 타입이 자주 변경되는 경우, 기계어로 변환 캐시해둬야하는 양이 매우 많아져 최적화의 장점이 퇴색된다. 이런 경우엔 그냥 인터프리터 방식으로 실행하는 것이 낫다.💡 - 그럼 인터프리터 언어가 더 좋은건가?
👉 Nope
위의 문제를 극복하기 위해AJITC
가 등장하게 되었는데 모든 코드를 일괄적으로 최적화하지 않고 반복 수행 정도에 따라 가중치를 두어 유동적으로 서로 다른 정도로 최적화 수준을 적용하는 방식이다.
Runtime Profiler
: JS는 프로토타입 기반으로 객체 지향을 지원하며, 개체가 생성된 이후에도 동적으로 프로퍼티와 메소드를 변경할 수 있다
: 런타임 이전에 변수 타입이 결정되는 정적 타입 언어 (JAVA, C++)과 달리 변수 타입이 존재하지 않으며 런타임에 변수 타입이 변경될 수 있다
: 함수를 객체 취급하며, 인수로 넘길 수 있어 함수형 프로그래밍을 지원한다
: 데이터를 임시 저장하는 곳으로 변수, 함수 값들을 저장하고 메모리를 할당하는 공간
: 코드가 실행되면 작업들의 실행 순서를 기록하고 하나씩 순차적으로 수행하는 공간
💡 JS 엔진은 싱글 쓰레드 언어로 콜스택이 하나밖에 존재하지 않는다면, 동시에 여러 작업을 수행할 수 없다. (동기식 언어)
그런데 어떻게 브라우저 환경에서 여러 작업을 진행되는 동안 Block이 일어나지 않고 비동기 작업을 처리할 수 있는건가?
자바스크립트 엔진은 싱글 쓰레드이지만, 자바스크립트가 실행되는 런타임 환경(브라우저, nodeJS)이 싱글 쓰레드 환경이 아니기 때문.
💡 자바스크립트가 '단일 스레드' 기반의 언어라는 말은 '자바스크립트 엔진이 단일 호출 스택을 사용한다'는 관점에서만 사실이다.
: 브라우저에서 제공하는 API. 자바스크립트 엔진에서 정의되지 않았던 setTimeout
이나 HTTP 요청(ajax) 메소드
, DOM 이벤트
등의 메소드를 지원
: 이벤트 발생 후, 호출되어야 할, 콜백 함수들이 기다리는 공간. 이벤트 루프가 정한 순서대로 줄을 서 있으므로 콜백큐라고도 부른다.
: 이벤트 발생시 호출할 콜백 함수들을 관리하고, 호출된 콜백 함수의 실행 순서를 결정
💡 이벤트 루프가 반드시 Call Stack이 비어져있는 상태에서만 Call Stack으로 Push 하는 이유는 자바스크립트라는 언어가 동기화 문제를 안는 것을 피하고 단일 스레드 언어라는 것을 보장해주기 위함이다.
단일 스레드 환경에서 함수가 실행되고 있는 도중에, 새로운 작업들을 계속해서 콜 스택에 밀어넣게 된다면, 작업의 진행 순서를 보장할 수 없는 동기화 문제가 발생하게 되기 때문
: 콜스택과 메모리 힙은 한정적인 자원이므로, 이 공간을 효율적으로 관리하기 위해 더 이상 효용가치가 없다고 판단되는 변수, 함수 등을 함수 실행 종료 후 메모리 힙에서 제거하는 동작을 수행한다.
💡 "더 이상 필요없는 오브젝트"를 "닿을 수 없는 오브젝트"로 정의한다.
roots 라는 오브젝트의 집합을 가지고 있다(자바스크립트에서는 전역 변수들을 의미). 주기적으로 가비지 콜렉터는 roots로 부터 시작하여 roots가 참조하는 오브젝트들, roots가 참조하는 오브젝트가 참조하는 오브젝트들... 을 닿을 수 있는 오브젝트라고 표시한다. 그리고 닿을 수 있는 오브젝트가 아닌 닿을 수 없는 오브젝트에 대해 가비지 콜렉션을 수행한다.
즉, 전역 환경에서 더 이상 참조할 수 없는 변수나 함수에 대해 가비지 콜렉션을 수행한다
: 자바스크립트 소스 코드를 토큰으로 변환한다. 이 과정을 렉시컬 분석(lexical analyze), 토크나이징(Tokenizing), 렉싱(Lexing) 등으로 부름
: 렉시컬 분석을 통해 만들어진 토큰 목록을 트리 구조로 만들며 (= AST(Abstract Syntax Tree)) 이 과정을 파싱(Parsing)이라고 부른다.
babel
,prettier
,jst2flowchart
에서 트랜스파일링을 진행할 수 있다.: AST를 바이트 코드로 변환한다.
다음 글에 이어서 👉 자바스크립트(JS) 엔진의 구성과 동작 원리 (2)