자바스크립트에서 시간 지연 후 함수를 호출하기 위하여 setTimeout()을 사용한다. setTimeout()을 수행할 경우 원하는 시간만큼 지연한 뒤 콜백 함수를 호출할 수 있다. 이 경우 각각의 지연 시간이 동일하게 나타날 수도 있는데 뒤에는 이런 문제를 해결하기 위하여 알아보도록 한다.


간단하게 1부터 10까지 더하는 예제를 만들어보자. 만약 1부터 10까지 더하는 함수를 만든다면 매우 쉽게 55를 얻을 수 있다. 하지만 우리는 아래와 같이 사용자에게 더하는 과정을 보여주려 한다.

문제: 1초에 1씩 더하고 추가한 값을 보여주기

그럼 문제를 해결해보자. 먼저 시간 지연이 없다면 코드가 어떻게 될까?


# 1부터 10까지 합 구하기


아래의 코드를 보자. 아래의 코드는 1부터 10까지의 합을 구하는 연산이다.

var startNum = 1;
var lastNum = 10;
var sum = 0;

for (startNum; startNum < lastNum+1; startNum++) {
  sum = sum + startNum;
  console.log("sum: " + sum);
}

위 코드를 실행하면 아래와 같은 결과를 예상할 수 있다.

sum: 1
sum: 3
sum: 6
sum: 10
sum: 15
sum: 21
sum: 28
sum: 36
sum: 45
sum: 55

여기까지는 큰 문제가 없다. 하지만 만약 1초 간격으로 합한 값을 출력하려면 결과는 어떻게될까? 아래의 코드를 보자.

var startNum = 1;
var lastNum = 10;
var sum = 0;

for (startNum; startNum < lastNum+1; startNum++) {
  setTimeout(function() {
    sum = sum + startNum;
    console.log("sum: " + sum);
  }, startNum * 1000);
}

위 코드는 1초 간격으로 sum을 출력한다. 하지만 결과는? 원했던 결과와 다르게 나타나게 된다. 아래의 결과를 보자.

sum: 55
. . .
. .
.
sum: 55


예상과는 달리 모두 55가 나타나게 된다. 뭐가 잘못된 것일까?
코드는 시간 순으로 적혀있지만 실제 sum을 구하는 연산은 setTimeout()이 나중에 호출하는 콜백함수인 익명함수에서 행하여진다. 이 경우 클로저가 발생하여 sum이라는 변수를 참조하기 때문에 결국 동일한 값들이 나타나게 되는 것이다.

이를 해결하기 위하여는 어떤 방법이 있을까?


# 클로저(closure)를 우회하는 방법


클로저를 우회하는 방법으로 아래의 방법을 사용할 수 있다.

! 클로저가 나타나는 내부의 익명함수 옮기기

클로저를 피하기 위하여 내부의 익명함수를 옮기고 필요한 변수를 인자로 넘기는 방법이다. 클로저가 내부함수에서 외부함수를 참조할때 생기므로 환경을 변화하는 방법이다.

var startNum = 1;
var lastNum = 10;
var sum = 0;

var sumNum = function(startNum, sum) {
  setTimeout(function() {
    console.log("sum: " + sum);
  }, startNum * 1000);
  
}

for (startNum; startNum < lastNum+1; startNum++) {
  sum = sum + startNum;
  sumNum(startNum, sum);
}

이제 아래 코드는 정상적으로 1초마다 해당 값을 반환하게 된다.
sum: 1
sum: 3
sum: 6
. . .
. .
.
sum: 55

​​​​​​이처럼 setTimeout()의 내부함수는 클로저가 발생하므로 목적에 따라 클로저를 활용하거나 우회할 필요가 있다.
code snippet widget