Event Loop의 동작에 따른 코드 실행 결과와 Closure 함수와의 관계에 따른 실행 결과를 간단한 예제를 통해 JavaScript 동작에 대한 보다 정확한 이해를 할 수 있다.
setTimeout은 Web API 에서 제공하는 함수로, JavaScript Engine이 코드를 읽으면서 Call Stack에서 수행할 때 바로 수행되는 것이 아니라 Web API는 대기실로 이동 하였다가 Task Queue로 setTimeout의 Callback 함수가 이동하는데, Call Stack 에 수행되는 작업이 없을 때 Task Queue에 존재하는 Callback 함수를 Call Stack 으로 가져와 해당 코드의 내용을 전부 수행한다.
일반 함수 반복
*동기
이기 때문에 반복문이 돌면서 함수가 호출된다.*
function getFunc(i) {
console.log(i);
}
for (var i = 0; i < 5; i++) { // let 도 동일
getFunc(i); // 동기로 동작
}
*// 결과
// 0
// 1
// 2
// 3
// 4*
Web API 함수 반복 : 자료형 var
사용
*비동기
이기 때문에 반복문이 끝나고 해당 함수가 호출된다.*
for (var i = 0; i < 5; i++) { *// var i = 0*
setTimeout(() => { // 비동기로 동작
console.log(i);
}, 1000);
}
console.log(i); // 5
*// 결과
// 5
// 5
// 5
// 5
// 5*
→ 'var i' 는 function level Scope를 가진다.
→ var 의 경우 반복문이 끝나도 var i
의 값은 아직 유효하다.
→ 먼저 Call Stack 이 수행되고 나서 Task Queue에 setTimeout(), setTimeout(), setTimeout() ... 이 쌓이고 반환 값은 5, 5, 5, ...
Web API 함수 반복 : 자료형 let
사용
for (let i = 0; i < 5; i++) { *// let i = 0*
setTimeout(() => { // 비동기로 동작
console.log(i);
}, 1000);
}
console.log(i); // error
*// 결과
// 0
// 1
// 2
// 3
// 4*
→ 'let i' 는 block level Scope를 가진다.
→ let 의 경우 반복문이 끝나면 let i
의 값은 유효하지 않다.
→ 콜백 함수의 자유 변수 i 는 클로저
로 인해 값을 참조하게 된다.
→ 먼저 Call Stack 이 수행되고 나서 Task Queue에 setTimeout(), setTimeout(), setTimeout() ... 이 쌓이고 반환 값은 0, 1, 2, ...
Web API 함수 반복 : 함수 사용
for (var i = 0; i < 5; i++) { *// var i = 0*
getClosure(i);
}
function getClosure(i) {
setTimeout(() => { // 비동기로 동작
console.log(i);
}, 1000);
}
*// 결과
// 0
// 1
// 2
// 3
// 4
// let i = 0 을 사용 시*
→ 함수가 반복 할 때 각 함수마다 고유의 scope가 존재하며, var i 의 값은 각 함수의 scope의 i 이므로 var 의 function level scope 의 영향을 받지 않는다. (var i 의 참조 관계를 끊어냄)
→ 콜백 함수의 자유 변수 i 는 클로저
로 인해 값을 참조하게 된다.
→ 먼저 Call Stack 이 수행되고 나서 Task Queue에 setTimeout(), setTimeout(), setTimeout() ... 이 쌓이고 반환 값은 0, 1, 2, ...