자바스크립트 개발자라면 루프 내에서 비동기 메서드를 사용할 때 발생하는 이상한 행동에 부딪힌 적이 있을 것입니다. 대표적인 예로
setTimeout
을 for
루프 안에서 사용하는 경우가 있습니다. 이 시나리오는 수년 동안 자바스크립트 인터뷰에서 꾸준히 나오는 문제였습니다. 이 블로그 포스팅에서는 이 문제가 왜 발생하는지 배경까지 깊이 파해쳐 보고, 여러 가지 해결 방법도 함께 논의해보겠습니다.목차
고전적인 문제
대부분의 개발자가 처음 부딪히는 고전적인 문제는 다음과 같습니다:
for (var i = 0; i < 5; i++) { setTimeout(() => console.log(i), i * 1000) }
이 코드를 실행하면 콘솔에 0부터 4까지의 숫자가 1초 간격으로 로그될 것으로 예상할 수 있습니다. 그러나 실제로는 숫자
5
가 다섯 번 로그됩니다.문제 이해하기
이 문제가 발생하는 이유는
var
키워드의 스코프 때문입니다. 자바스크립트에서 var
는 함수 스코프입니다. 이는 변수 i
가 선언된 함수 내에서나 전역적으로 접근 가능하다는 것을 의미합니다. for
루프의 경우, setTimeout
함수가 실행될 때까지 루프가 이미 완료되어 i
는 5
의 값을 가지게 됩니다.해결책
let
사용하기
이 문제를 해결하는 가장 간단한 방법은
var
대신 let
을 사용하는 것입니다. let
키워드는 블록 스코프이므로 각 반복마다 자체 스코프를 갖게 됩니다.for (let i = 0; i < 5; i++) { setTimeout(() => console.log(i), i * 1000) }
setTimeout
의 세 번째 인자 사용하기
다른 해결책으로는
setTimeout
의 세 번째 인자를 사용하는 것이 있습니다. 이를 통해 함수에 인자를 전달할 수 있습니다.for (var i = 0; i < 5; i++) { setTimeout((capturedI) => console.log(capturedI), i * 1000, i) }
IIFE 사용하기
IIFE(즉시 실행 함수 표현식)를 사용해 각 반복마다 새로운 스코프를 생성할 수도 있습니다.
for (var i = 0; i < 5; i++) { ((capturedI) => setTimeout(() => console.log(capturedI), i * 1000) )(i); }
다른 예제와 함정
자바스크립트에서 스코프 문제를 이해하는 것은
setTimeout
에만 국한되지 않습니다. 이 지식은 프로미스나 async/await
과 같은 다른 비동기 작업을 처리할 때도 중요합니다.프로미스와의 예제:
for (var i = 0; i < 5; i++) { Promise.resolve(i).then((capturedI) => console.log(capturedI)) }
var
를 사용하면 여기서도 유사한 문제가 발생합니다. let
을 전환하거나 다른 스코프 캡처 기술을 사용하면 문제가 해결됩니다.결론
자바스크립트의 스코핑과 타이밍의 미묘한 부분을 이해하는 것은 중요합니다, 특히 루프 내에서 비동기 작업을 처리할 때는 더욱 그렇습니다.
setTimeout
을 루프 안에서 사용하는 고전적인 문제는 모든 자바스크립트 개발자가 알아야 할 언어의 이상한 점을 잘 보여줍니다.변수를 적절하게 캡처하는 방법을 이해함으로써 더 예측 가능하고 버그가 없는 코드를 작성할 수 있습니다. 이는 당신을 더 나은 개발자로 만들 뿐만 아니라, 다른 사람들도 당신의 코드를 더 쉽게 이해하고 유지보수할 수 있게 해줍니다.
읽어주셔서 감사합니다. 이 포스트가 유용하다고 생각되면 다른 사람들과 공유해 주세요. 행복한 코딩 되세요!