JavaScript timer의 동작에 대해서 알게 되었음.
How JavaScript Timers Work, John Resig
http://ejohn.org/blog/how-javascript-timers-work/
작성된지는 꽤 오래전 글이라 다른 블로그에서 잘 다루고 있음.
http://holdonj.tistory.com/9
내용을 대충 정리하면 아래 두 함수는 JavaScript 코딩 중에 일정 주기로 코드를 실행되게 할 때 사용하는 함수들이다.
- setTimeout(fn, delay) : delay 이후 실행되는 single timer
- setInterval(fn, delay) : delay 마다 실행되도록 하는 주기적인 timer
함수의 효과는 동일하게 느껴 지지만 실제 사용할 때는 아래 사항들을 알고 사용해야 한다.
- JavaScript timer의 delay는 보장되지 않는다.
- JavaScript 코드는 실행가능한 조건에서 실행되며 이는 웹브라우저가 single thread상에서 비동기적 event들(mouse click, timer 등)을 처리하기 때문이다.
이를 아래 그림을 통해 자세히 설명 하고 있다.
위 그림 내에서
왼쪽의 숫자들은 시간(ms단위)를 의미하고, 오른쪽은 비동기적 event들을 나타내고,
중간의 블럭들은 실행되는 JavaScript 코드들이다.
* JavaScript 코드들은 single thread 상에서 처리되므로 하나의 한 block만 처리된다.
시간 순서대로 보면
왼쪽의 숫자들은 시간(ms단위)를 의미하고, 오른쪽은 비동기적 event들을 나타내고,
중간의 블럭들은 실행되는 JavaScript 코드들이다.
* JavaScript 코드들은 single thread 상에서 처리되므로 하나의 한 block만 처리된다.
시간 순서대로 보면
- 20ms 내에서는 순차적으로 timer, mouse click, interval event들이 발생된다.
. mouse click 발생 시 event cb(callback)를 Queue에 등록한다.
. 10ms 이후 등록된 timer cb을 실행되려 하지만 아직 JavaScript 코드가 실행중이므로 Queue에 등록한다. (Queue : mouse click event cb, timer cb)
- 20ms 전, JavaScript 코드가 완료되면 Queue의 첫번째 mouse click event cb을 처리한다.
. 20ms 시점에 mouse click event cb처리 도중 interval cb이 실행되려 하지만 실행할 수 없어 Queue에 등록한다. (Queue : timer cb, interval cb)
- 30ms 전, mouse click event cb이 완료되고 Queue의 첫번째 timer cb이 실행된다.
. 30ms 시점에 interval cb을 실행하려 하지만 역시나 실행할 수 없는 상태라 Queue에 등록해야 하지만 브라우저에서 drop 시킨다.
> 긴 코드의 실행 시 발생되는 interval cb이 모두 Queue 등록되어 처리가 된다면 코드 완료 후 연속적인 interval 등록 코드들이 호출 되므로 브라우저에서 interval cb의 기등록 여부를 판단하여 drop 하는 것으로 보임.
. 35ms 이후 timer cb이 완료 되고 Queue에 있던 interval cb이 실행된다.
- 40ms, interval cb이 실행되려 하지만 역시나 실행할 수 없는 상태라 Queue에 등록 (Queue : interval cb)
. 40ms 이후 intervale cb이 완료되고 Queue에 남아 있던 interval cb이 실행된다. (Queue : nothing)
정리해보면
- JavaScript engine은 single thread 기반이라 비동기 event들을 queuing하여 실행한다.
- setTimeout, setInterval은 비동기 코드를 실행하는 방법이 근본적?으로 다르다.
- timer cb의 실행이 block될 경우 다음 가능한 시점까지 delay된다.
- interval cb의 실행 시간이 delay보다 크다면 delay 없이 반복적으로 계속 실행 될 수 있다.
추가로 예제 코드를 보면
- setTimeout(function(){
- /* Some long block of code... */
- setTimeout(arguments.callee, 10);
- }, 10);
- setInterval(function(){
- /* Some long block of code... */
- }, 10);
함수 정의 상으로는 두 코드 모드 10ms 간격으로 실행되는 것이 맞지만
setTimeout은 long code block이 실행된 뒤 10ms 이후에 실행 시도 하는 것이고
setInterval은 long code block을 이전 코드 실행완료 여부에 상관없이 10ms 간격으로 실행 시도 하는 것으로 차이가 있다는 것을 판단할 수 있을 것이다.
- 추가로 10ms 이하로 시간에 특정 코드를 호출하는 방법에 대한 포스팅
setTimeout with a shorter delay, David Baron
: http://dbaron.org/log/20100309-faster-timeouts