클로저와 비동기 실행 순서

let i = 0;
  
while (i < 2) {
  setTimeout(() => {
    console.log(i);
  }, 10);
  
  i++;
}

console.log(i);

t=0

  • i=0 → 10ms 후 타이머 콜백 등록
  • i=1 → 10ms 후 타이머 콜백 등록
  • i=2 → while 종료
  • 동기 코드, console.log(2) 출력

t=10ms

  • i=0 타이머 콜백 실행
    • i 는 2로 증가되어 있는 상태, 2 출력
  • i=1 타이머 콜백 실행
    • i 는 2로 증가되어 있는 상태, 2 출력

타이머 콜백은 클로저가 된다.

타이머 콜백이 생성되는 시점에 i 라는 변수를 기억한다.

메인 함수가 종료되어도 타이머 콜백은 i 라는 변수를 기억한다.

타이머 콜백이 모두 실행되면 그제서야 i 가 가비지 컬렉션 대상이 된다.

while (i < 2) {
    ((num) => {
        setTimeout(() => console.log(num), 10);
    })(i);
    
    i++;
}

즉시 실행 함수로 독립적인 num 변수를 생성한다.

타이머 콜백은 독립적인 num 변수를 참조하는 클로저가 된다.

for (let i = 0; i < 2; i++) {
    setTimeout(() => console.log(i), 10);  // 0, 1 출력
}

마찬가지로 타이머 콜백은 루프마다 생성되는 독립적인 변수를 참조한다.