[그림 참조]https://baeharam.github.io/posts/javascript/jshow-javascript-works/
자바스크립트는 위와 같은 구조를 가지고 실행된다. 자바스크립트에서 실행되는 함수는 stack에 들어가고 맨 위 부터 차례대로 실행되게 된다. stack은 LIFO(Last In First Out)에 따라 실행되기 때문이다.
function test(){
console.log('test');
}
function qux(){
test();
console.log('qux');
}
function bar(){
qux();
console.log('bar');
}
function foo(){
bar();
console.log('foo');
}
foo();
위와 같은 코드가 실행된다면 foo, bar, qux, test 순으로 스택에 쌓이게 된다. 그리고 가장 마지막에 실행된 test부터 qux, bar, foo 순으로 실행되게된다.
<출력>
test
qux
bar
foo
요렇게 출력될 것이다.
console.log(1+1);
setTimeout(()=>{console.log(2+2)}, 1000);
console.log(3+3);
이 코드를 실행하면 어떤 결과가 출력될거라고 생각하는가? 나 같이 자바스크립트의 작동원리를 몰랐던 상태였다면 당연히 "2 4 6"순으로 출력될 것으로 예상할 것이다.
<출력>
2
6
4
하지만 출력하게 되면 뜬금없이 4가 마지막에 실행되는 것을 볼 수 있다.
스택에 setTimeOut, Ajax요청, 이벤트리스너와 같이 정해져 있는 몇몇 API에 대해서 자바스크립트는 비동기처리를 요구한다.
작동 방법은 다음과 같다.
setTimeOut이 stack에 들어오게되면 이거 뭐야 대기실로 보내!
-> 대기실에서 1초 동안 기다려야지..
-> 시간 다 됐다. 큐로 가야지!!
-> 아.. 스택 전부 빌때까지 못 간대 ㅜㅜ, 스택이 다 비면 가자.
-> 스택이 다 비게 되면 setTimeOut에 있던 콜백함수들이 스택에 쌓이게 되고 이것이 실행되는 것이다.
그래서 위와 같이 4가 제일 마지막으로 출력되는 것이다. setTimeout의 설정 시간을 0밀리세컨드로 한다고 하더라도 스택이 다 빌때까지 들어가지 못 하기에 출력값은 동일하다.
for (var i = 0; i<10; i++){
setTimeout(()=>{console.log(i)},2000);
};
그렇다면 위와 같은 코드의 실행값은 무엇이 될까??? "0 1 2 3 4 5 ... 9"일까?
아니다. "10 10 10 ... 10"이 실행되게 된다.
i=0일때 stack에 가자마자 setTimeout은 대기실로 보내버리게된다. 이것이 반복되게 되면 백그라운드에서 setTimeout 6개가 2초를 기다리고 있게 될 것이다. 하지만 for문의 i는 스택에서 차례대로 실행되어 결국 i=10을 heap에 저장하게 된다. 그래서 후에 스택으로 돌아온 setTimeout의 콜백함수들은 heap의 i값을 들고오게 되고 10이 10번 호출되게 되는 것이다.
위와 같을 때 for문에서 let 키워드를 사용하시면 for문이 반복될 때마다 새로운 렉시컬 환경을 생성합니다. 그렇게하면 i값을 기억하기 때문에 올바른 결과값을 나타낼 수 있게 된다.
for(i=1; i<6; i++){
(function(x){
setTimeout(function(){
console.log(x);
}, 1000*x);
})(i);
}
혹은 이와 같이 즉시실행함수를 사용할 수도 있다.
콜백, 프라미스, async await을 통해서 다룰 수 있다.! 이것은 다음 포스팅에서 다루도록 하겠다.