자바스크립트 작동원리에 대해 다시 한 번 정리를 하고 싶었다. 늘 대략적으로 알고는 있었지만 정확하게 누가 물어본다면 자세하게 설명할 수 있을 정도로 학습이 필요하다 생각했고 오늘 이 시간을 통해 정리를 한 번 야무지게 해보겠다ㅎㅎ
자, 먼저 JS를 동작하게 해주는 엔진이 있다. 여기서 엔진은 JS코드를 읽고 개발자가 원하는 실행 동작을 할 수 있도록 한다.
구글: V8 엔진
파이어폭스: SpiderMonkey
사파리: Webkit
등등 위 JS엔진이 코드를 읽어 준 후 각 변수와 객체 배열 등 메모리를 할당하고 함수를 할당 및 실행한다.
그렇다면 위 엔진은 어떤 방식으로 코드를 읽고 실행할까?
결론부터 정리하자면 다음과 같은 순서로 JS엔진은 작동한다.
코드를 전체적으로 한 번 싹 훑는다. 그래서 "전역 실행 컨텍스트를 형성한다."
바로 Callstack에 전역 실행 컨텍스트를 형성한다 !
이 전역 실행 컨텍스트는 가장 바깥 스코프에 있는 즉, 전역 스코프에 있는 함수나 변수를 Callstack에 저장하고 이 전역 컨텍스트는 코드가 모두 실행되고 마지막에 빠져나간다.
전역 컨텍스트가 형성 될 때 Heap에 배열, 객체와 같은 참조형 자료구조가 저장된다. stack에는 메모리주소와 변수 함수 등이 저장된다
함수를 위에서부터 아래 방향으로 실행한다. 이때 JS엔진은 싱글스레드를 기반으로 하여 Callstack은 1개 밖에 존재하지 않는다. 그럼 비동기적으로 처리되는 함수가 Callstack에 쌓였을 때는 어떻게 될까?
비동기 함수를 마주했을 때 JS엔진은 비동기함수를 browser web API 에서 따로 처리해 줍니다. 처리를 다하면 위 비동기 함수들은 Callback Queue에 저장이 된다.
Callstack이 비어있을 때!! 이때 Callback Queue에 저장된 비동기 함수가 실행이 되어 빠져나간다.
이를 이벤트 루프 ( event loop) 라고 한다!!
이제 이해가 잘 된다. 이 과정을 이해하는데 꽤 시간이 걸렸던 거 같다. JS를 배운지 얼마 되지 않았을 때도 이러한 과정을 이해하려했는데 지금은 그때보다 이해가 더 잘된다. 그림으로 한번 표현해보겠다.
참고로 필자는 그림을 정말 못그린다 그래도 해보겠다 ㅋㅋ
function one(){
const haha = "hahaha"
console.log(haha)
}
function two(){
console.log("hoho")
}
function three(){
return "What"
}
console.log(three)
two()
one()
그림이 엉망이긴하지만 텍스트로 설명을하면 일단 전역실행컨텍스트는 전역 스코프 내부에 있는 모든 변수와 함수 등에 대한 데이터를 메모리 heap과 stack에 저장한다. 이때 heap에 저장되는 건 참조형 자료구조: 배열, 객체 등이 있다.
그리고 위에서부터 함수가 실행된다. console.log()가 실행되지만 내부에 three라는 함수가 매개변수로 들어가 있어 three가 실행되고 . 그후 "What"라는 결과 값을 가져온 후 callstack에서 사라진다. 그리고 console.log("What")가 출력된다.
다음 함수인 two,one이 차례로 실행되고 two함수는 내부의 console.log()가 실행되고 callstack에서 사라진다. 그 후 one은 one내부의 실행 컨텍스트가 형성되고 이를 참조하여 console.log()가 실행된 후 사라진다.
여기서 비동기 함수가 껴있으면 어떻게 될까?
다음과 같이 실행된다.
console.log('시작!');
setTimeout(function timeout(){
console.log('1초가 지났습니다');
});
console.log('끝!');
다음과 같은 코드가 있을 때 결과 값이
시작
1초가지났습니다
끝
이렇게 출력이 될까?? 결론은 그렇지 않다.
먼저 console.log(시작
)은 callstack에 들어가고 바로 탈출한다. 그럼 시작이 출력이된 후 setTimout이라는 비동기 함수를 마주한다. 그럼 setTimeout은 browser내부의 webApi에서 따로 처리를 해주러 callstack에서 탈출한다. 그리고 그 다음 console.log(끝
)이 출력되고
WebAPi에서 비동기 함수를 모두 처리한 후 callback Queue에 함수를 보낸다. 이때 stack이 비어있다면?? 이벤트 루프를 통해 callStack으로 함수가 들어가 실행 된 후 종료된다.
시작
끝
1초가지났습니다
가 출력이 된다.
도움을 받은 사이트가 있다.
메모리힙도 데이터를 저장하는 공간이고 stack도 데이터를 저장하는 공간인데 무엇이 다를까?
memory heap은 참조형 데이터가 저장이 된다.
stack은 변수,함수, 참조형 데이터의 위치 등이 저장이 된다.
메모리 힙은 동적으로 할당된 데이터가 저장되는 영역입니다. 메모리 힙은 실행 중인 프로그램에서 객체, 배열, 함수 등과 같은 참조 타입의 데이터를 저장하기 위해 사용됩니다.
자바스크립트에서 변수에 할당되는 원시 값(숫자, 문자열, 불리언 등)은 메모리 힙이 아닌 스택(Stack)에 직접 저장됩니다. 그러나 객체와 배열 같은 참조 타입의 값은 힙에 저장되고, 스택에는 힙 내의 메모리 주소만 저장됩니다.
-chat gpt-
그렇다. callback queue는 call stack이 비어있는 순간을 계속 주시한다. 그리고 비어있는 순간 침투! 해서 함수를 실행시켜준다.
-레전드 블로그1 에서 발췌-
event loop는 Call Stack 비어있는지를 주기적으로 확인하여 Callback Queue에서 Callback function을 가져와 Call Stack에서 Javascript 코드가 실행될 수 있도록 돕는 역할을 합니다. event loop가 반복적으로 Call Stack이 비어있는지 확인 하는 것을 tick이라고 합니다.
정확히는 event loop가 비어있는지 주기적으로 확인해준다.
이를 tick 이라고한다.
내일 실행 컨텍스트에 대해 제대로 정리를 할 예정인데 미리 살짝 정리를 해보자면 다음과 같이 정의할 수 있다.
실행 컨텍스트: 함수를 실행시키기 위한 환경(준비)
JS엔진은 코드를 읽기 시작하거나 함수를 실행할 때 그 scope에 맞는 실행 컨텍스트를 형성하는데 이때, Scope chaning과 Hoisting이 발생한다..!
위 동영상에서 정말 정리를 잘해주셔서 필자도 이해할 수 있었다. 다음 시간에 위 동영상을 기반으로 조개소년의 벨로그도 업데이트 드가자~