2014년 11월 24일 월요일

JavaScript Timer가 어떻게 동작하는가?

얼마전 JavaScript timer가 궁금해서 찾던 중 아래 글을 발견하고
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만 처리된다.

시간 순서대로 보면 

- 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 없이 반복적으로 계속 실행 될 수 있다.


추가로 예제 코드를 보면

  1.   setTimeout(function(){
  2.     /* Some long block of code... */
  3.     setTimeout(arguments.callee, 10);
  4.   }, 10);
  5.   setInterval(function(){
  6.     /* Some long block of code... */
  7.   }, 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

댓글 없음:

댓글 쓰기