프론트엔드 개발자를 목표로 한다면 당연히 다룰줄 알아야하는 언어 바로 자바스크립트입니다. 프론트엔드 뿐만 아니라 백엔드 서버프로그래밍에도 사용되고 있는 자바스크립트는 웹 개발자라면 필수로 다루어야할 언어입니다.
웹 개발자라면 중요한 자바스크립트 지금부터 이 언어의 동작 원리에 대해 알아보겠습니다.
자바스크립트 엔진은 자바스크립트 코드를 실행하는 프로그램 혹은 인터프리터를 말합니다. 자바스크립트 엔진은 표준적인 인터프리터로 구현될 수도 있고 혹은 자바스크립트 코드를 바이트코드로 컴파일하는 저스트인타임(just-in-time) 컴파일로러 구현할 수도 있습니다.(인터프리터와 컴파일러의 차이(https://velog.io/@jaeyunn_15/OS-Compiler-vs-Interpreter) 참조) 대표적인 자바스크립트 엔진으로는 구글의 V8엔진이 있습니다.
출처 : https://blog.sessionstack.com/how-does-javascript-actually-work-part-1-b0bacc073cf
메모리 할당이 이루어지는 곳
코드가 실행되면서 스택프레임이 쌓이는 곳.
Memory Heap
원시타입은 콜스택에 저장되고, 참조타입은 메모리힙에 저장된다.
참조타입 데이터(핑크색 변수 b, c, d)
배열, 객체, 함수 등은 참조타입이므로 메모리 힙에 저장된다.
참조타입 데이터가 저장된 메모리힙의 주소값은 콜스택에 각각 저장된다.
메모리힙의 주소값이 저장된 콜스택의 주소값은 각각 변수 b, c, d에 저장된다.
.
출처: https://curryyou.tistory.com/276 [카레유]
Call Stack(호출스택)
자바스크립트는 기본적으로 작업을 싱글스레드로 처리합니다.(멀티가 되지 않고 하나씩 처리함) 즉, 하나의 호출 스택을 사용합니다. 호출스택은 코드가 실행되면 코드의 내부의 실행 순서를 기록해 놓고, 하나씩 순차적으로 진행할 수 있도록 도와주는 곳입니다. 함수를 실행하면 해당 함수의 기록을 스택 맨 위에 추가(Push)하고 우리가 함수의 결과 값을 반환하면 스택에 쌓여있던 함수는 제거(Pop) 되는 원리입니다.
코드
function multiplyNumber(num1, num2) {
return num1 * num2;
}
function printSquare(x) {
let n = multiplyNumber(x, x);
console.log(s);
}
printSquare(5);
위코드의 순서는 아래 그림과 같습니다.
1. printSquare 실행
2. multiplyNumber 실행
3. multiplyNumber 반환
4. console.log 실행
5. console.log 반환
6. printSquare 반환
출처: https://blog.sessionstack.com/how-does-javascript-actually-work-part-1-b0bacc073cf
그렇다면 콜스택 내에서 문제가 생기는 경우는 어떤 경우가 있을까요??
만약 재귀 함수를 면밀히 테스트하지 않을 경우 자기 자신을 계속해서 호출하게되고
이는 콜 스택의 최대 크기를 넘어서면서 에러를 발생시킵니다. 밑에 샘플 코드를 살펴보겠습니다.
function foo() {
foo();
}
foo();
foo 함수는 재귀적이어서 종료조건이 없이 계속 자기 자신을 호출하게 됩니다. 따라서 동일한 함수가 콜 스택에 반복해서 추가됩니다.
이렇게 계속 추가가 되기 때문에 스택 수가 콜 스택 크기를 넘게 되고 그렇게 되면 브라우저는 아래와 같은 에러를 보내게 됩니다.
위와 같은 에러 말고도 만약 콜스택 내에 수행시간이 긴 함수가 있다면 어떻게 될까요??
콜스택에 쌓여있는 함수 중에 복잡한 문제를 해결해야하는 함수가 있다고 가정해봅시다.
이렇게 되면 브라우저는 이 함수를 수행하기 전까지 렌더링을 할 수도 다른 코드를 수행할 수도 없는 blocking 상태가 되어버립니다.
이와같은 문제를 해결하려면 어떻게 해야 할까요?
해결책은 비동기 콜백 (asynchronous callbacks)을 사용하는 것입니다.
다음 그림을 보며 같이 비동기 콜백의 과정에 대해 알아봅시다.
왼쪽 그림은 우리가 좀 전에 봤던 자바스크립트 엔진입니다. 근데 옆에 있는 WebAPIs, Event Loop, Callback Queue는 무엇일까요?
Web APIs
Web API란 브라우저에서 제공하는 API 로 DOM, Ajax, Timeout 등이 있습니다.
Call Stack에서 실행된 비동기 함수는 Web API를 호출하고,
Web API는 콜백함수를 Callback Queue에 밀어 넣습니다.
여기서 콜백함수란?
자바스크립트에서는 함수가 실행이 끝나면, 다음에 실행할 일을 정할 수 있는데 이 것을 Callback이라고 부릅니다. 즉, callback Function은 함수가 정해놓은 일이 끝난 뒤, 후속으로 하는 일을 알려주는 함수입니다. 간단히 말하면 함수에 파라미터로 들어가는 함수입니다.
예를 들어 봅시다.
code 라면끓이기 순서
물 끓이기(파라미터){
console.log("물이 끓어요")
파라미터()
}
스프넣기(){
console.log("스프를 넣었어요")
}
물 끓이기(스프넣기)
Callback Queue
Callback Queue란 비동기적으로 실행된 콜백함수가 보관 되는 영역이다.
예를 들어 그림 같이 addEventListener에서 click이 되어야 실행되는 onClick 함수라던가
설정한 시간이 지나야 실행되는 setTimeout 함수 등이 있습니다.
큐는 스택과 다르게 선입선출(FIFO)방식을 따릅니다.
Event Loof
Event Loop는 Call Stack과 Callback Queue의 상태를 체크하여,
Call Stack이 빈 상태가 되면, Callback Queue의 첫번째 콜백을 Call Stack으로 밀어넣는 역할을 하고 있습니다.
정리
1. 코드가 실행되면 Call Stack에 쌓입니다.
2. Call Stack은 선입후출이기 때문에 가장 나중에 들어온 함수부터 모든 함수가 차례대로 실행되게 됩니다.
3. 만약 Call Stack에 비동기 함수 차례가 와서 실행된다면 Web API가 호출됩니다.
4. Web API는 비동기함수의 콜백함수를 Callback Queue에 밀어넣습니다.
5. Event Loop는 Call Stack이 빈 상태가 되면
Callback Queue에 있는 첫번째 콜백을 Call Stack으로 이동시킨다.
코드예시
console.log('시작!');
setTimeout(function timeout(){
console.log('1초가 지났습니다');
},1000);
console.log('끝!');
console.log(‘시작’)코드가 call stack에 들어가게 되고 실행이 됩니다.
오타
setTimeout(function(){
console.log('1초가 지났습니다');
},1000); 가 맞습니다.
Call Stack에 setTimeout 함수가 들어갑니다.
6. event loop가 Call Stack이 비어있는지 확인하고, timeout() 함수를 call Stack으로 보냅니다.
7. timeout 함수 안에 있던 console.log(‘1초가 지났습니다’) 코드가 호출됩니다.
8. 모든 함수가 호출되고 Call Stack이 비워집니다.
정리하자면 event loop는 Call Stack 비어있는지를 주기적으로 확인하고 Callback Queue에서 콜백함수를 가져와 Call Stack에서 Javascript 코드가 실행될 수 있도록 돕는 역할을 합니다.
https://blog.sessionstack.com/how-does-javascript-actually-work-part-1-b0bacc073cf
https://velog.io/@namezin/javascript-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC
https://blog.toycrane.xyz/%EC%A7%84%EC%A7%9C-%EC%89%BD%EA%B2%8C-%EC%95%8C%EC%95%84%EB%B3%B4%EB%8A%94-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC-c7fbdc44cc97
https://velog.io/@thms200/Event-Loop-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A3%A8%ED%94%84
https://engineering.huiseoul.com/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%9E%91%EB%8F%99%ED%95%98%EB%8A%94%EA%B0%80-%EC%97%94%EC%A7%84-%EB%9F%B0%ED%83%80%EC%9E%84-%EC%BD%9C%EC%8A%A4%ED%83%9D-%EA%B0%9C%EA%B4%80-ea47917c8442
https://curryyou.tistory.com/276