Javascript: 타이머는 어떻게 동작하는가? :: 마이구미
이 글은 자바스크립트 내부에서의 setTimeout, setInterval 과 같은 타이머들의 동작을 알아본다.
타이머들은 비동기로 처리되는데 이와 관련된 싱글 스레드, 비동기 처리등과 같은 또한 얻을 수 있을 것이다.
참고 자료 - https://johnresig.com/blog/how-javascript-timers-work/
글의 주제는 두 가지 의문을 가지고 글을 진행할 것이다.
첫번째 의문은 다음과 같다.
자바스크립트에서 타이머 관련 함수는 2가지로 볼 수 있다.
- setTimeout() - 일정 시간 뒤에 함수가 실행된다. * ms(1000분의 1초)
- setInterval() - 일정 시간마다 함수가 실행된다.
즉, 지연시간(delay)을 조작할 수 있다.
하지만 100ms 후 실행을 원하는 함수가 있을 때, 정확한 시간인 100ms 를 보장하지는 않는다.
두번째 의문은 다음과 같다.
setTimeout(function(){ /* Some long block of code... */ setTimeout(arguments.callee, 10); }, 10); setInterval(function(){ /* Some long block of code... */ }, 10);
위 2가지는 기능으로는 같아보이지만, 내부적으로는 다르게 동작한다.
기본적으로 자바스크립트는 싱글 스레드를 통해 동작한다는 사실을 알고 있을 것이다.
위의 의문점을 해결하기 위해서는 자바스크립트의 싱글 스레드를 이해해야한다.
싱글 스레드는 단순히 동시에 할 수 있는 일은 오로지 하나밖에 못한다고 보면 된다.
비동기 이벤트에 대한 흐름의 다이어그램은 다음과 같다.
위 그림은 각 블록으로 나눈 형태로, 각 블록은 실행되는 영역을 의미한다.
예를 들면 첫번째 블록은 자바스크립트가 약 18ms 동안 실행되었고, 두번째는 마우스 이벤트 실행이 약 11ms 동안 실행되었다.
위에서 아래방향으로 실행된다고 보면된다.
Javascript 블록에서 상황의 순서는 다음과 같다.
- setTimeout 타이머가 설정되었다.
- 마우스 클릭 이벤트가 발생했다.
- setInterval 타이머가 설정되었다.
- 타이머가 실행되었다.
현재 상황에서 실행되는 건 Mouse Event 와 setTimeout 이 실행된다.
하지만 실제로는 즉시 실행되지 않고 큐에 넣어 대기하게 된다.
이유는 아직 Javascript 블록의 실행이 끝나지 않았기 때문에 다른 처리를 할 수 없다. (싱글 스레드)
그 후 Javascript 블록이 끝이 나면, 내부에서는 큐에서 대기하는 처리가 있는지 확인한다.
이 부분이 Mouse Click Callback 블록전에 있는 "What's waiting?" 을 의미한다.
그 후 큐에서 가져온 후, Mouse Click Callback 블록이 생기게 되고 Timer(setTimeout) 은 여전히 가능한 시간까지 대기하게 된다.
Mouse Click Callback 블록에서 1번째 Interval 콜백이 발생하는 것을 볼 수 있다.
아직 처리중이기 때문에 이 또한 큐에서 대기하게 된다.
Mouse Click Callback 블록이 끝이 나면, 큐에서 Timer 를 가져온다.
Timer 블록에서 2번째 Interval 콜백이 발생했지만, Timer 핸들러가 실행되고 있기 때문에 처리되지않고 드랍된다,
반대로 Timer 블록이 끝난 후, Interval 블록에서 3번째 Interval 콜백이 발생했을 때는 드랍되지 않고 그대로 처리되는 모습을 볼 수 있다.
즉, Interval 의 경우에는 이전 콜백 실행 여부와 상관없이 10ms 마다 실행을 시도한다.
반대로 Timer 는 실행되고 있는 이전 콜백이 완료를 기다린 후에 10ms 이후에 실행을 시도한다.
2번째 Interval 블록이 끝이 나면, 실행되는 블록과 큐에는 아무것도 없기 때문에 빈 공백을 볼 수 있다.
그로 인해 50ms 에 발생되는 Interval 콜백은 즉시 실행되는 모습을 볼 수 있다.
이러한 흐름을 통해 두번째 의문의 답을 추측할 수 있다.
setTimeout 은 항상 이전의 콜백의 실행 후로부터 지연시간을 갖게 된다.
setInterval 은 이전 콜백 실행 여부와 상관없이 항상 지연시간마다 실행하려고 시도한다.
결론적으로 요약한 결과는 다음과 같다.
- 자바스크립트 엔진은 오직 싱글 스레드만을 가짐으로써, 비동기 이벤트들을 큐에 대기하게 한다.
- setTimeout 과 setInterval 은 근본적으로 다르게 실행된다.
- setTimeout 과 setInterval 은 즉시 실행될 수 없는 상황이라면, 실행 가능할 때까지 지연돼서 시간을 보장할 수 없다.
- Interval 의 경우 실행주기가 지연시간보다 길다면, 지연없이 연속적으로 실행을 보장할 수 있다.