How Javascript Timer Work

making web/javascript 2011.06.11 14:36

초짜일 때 javascript timer가 어떻게 작동하는지 잘 이해해둬야 한다. 종종 예상치 못하게 동작할 때가 있는데 이게 다 single thread이기 때문이다. timer를 생성하고 조작하는 세 개의 함수를 예제를 통해 살펴보자.

  • var id = setTimeout(fn, delay);
    delay 이후에 fn이 한 번만 실행되는 타이머 생성. 반환되는 timer id값은 timer 중단시에 사용된다.
  • var id = setInterval(fn, delay);
    매 delay마다 fn이 실행되는 timer 생성. timer가 중단될 때까지 계속 실행됨
  • clearInterval(id); clearTimeout(id); 
    timer 생성시에 반환된 timer id로 timer 중단시킴.

timer에 대해 파들어가기 전에 기억해야 할 것은, timer는 의도한대로 동작한다는 걸 보장하지 않는다는 것이다. 브라우저에서 javascript는 single thread로 실행되기 때문에 비동기 이벤트(마우스 클릭이나 timer)는 실행 가능한 상황에서만 동작한다. 아래 좋은 예제 그림이 있다.

이 그림을 제대로 이해한다면, javascript 비동기 실행이 어떻게 작동하는지 느낌이 올 것이다. 단순한 1차원 그림이다. 세로축은 밀리초 단위의 시간이고, 파란 박스들은 실행된 javascript를 나타낸다.보면, 첫 번째 Javascript 블럭은 18ms 정도 실행되었고, mouse click callback 블럭은 11ms 쯤 실행되었다.

Javascript는 한 번에 하나의 코드 조각이 실행될 수 있기 때문에(single thread니까) 각각의 블럭들은 다른 비동기 이벤트(마우스 클릭, timer, ajax 요청이 끝났을 때 등...) 진행을 "blocking"한다. queue에 쌓여서 실행 대기 상태가 된다.(브라우저마다 다르지만, 단순하게~)

첫 번째 Javascript 블럭을 보면 두 개의 timer가 생성되었다. 10ms setTimeout, 10ms setInterval! 10ms 후에 timer가 실행되나 한 번 보자. 보시다시피, 실행되지 않는다! 실행되어야 할 fn은 실행 가능할 때 실행되겠다며 queue에 들어가셨다.

첫 번째 javascript block에는 8ms쯤에 mouse click도 발생했다. mouse click의 callback 함수 역시 바로 실행되지 못하고 나중에 실행하시겠다며 queue로 들어가셨을 테다.

javascript block이 끝나면 브라우저가 물어본다. 실행 대기하고 계신 분 있냐고? mouse click handler와 timer callback이 손을 들지만 먼저 들어와계셨던 mouse click callback를 실행하게 된다(그림에서 약 11ms 동안 실행됨). 그럼 timer callback은? 실행 가능한 다음 기회를 노린다.

mouse click handler가 실행되는 동안 10ms interval이 발생했지만 역시 queue로 들어가게 된다. 그 다음 10ms interval이 발생하면? 또 queue에 들어갈까? 큰 블럭의 코드가 실행 중이라고 했을 때 그 간의 모든 interval callback이 queue에서 실행을 기다리고 있을까? 그렇진 않다. 큰 블럭의 코드의 실행이 끝났을 때 모든 interval callback들이 다다다다~~ 실행될테니까. interval callback인 경우에 브라우저는 한 놈만 queue에 유지한다고 생각하면 되겠다. 그래서 30ms쯤에 10ms interval이 발생해도 그냥 dropped된 것이다. 이미 실행대기 queue에는 interval callback이 있으니까.

세 번째 10ms interval이 발생했을 때를 보면, interval callback이 실행 중임을 확인할 수 있다. interval은 지금 뭐이가 실행되고 있는지 전혀 상관치 않는다. 지금 실행 안되면 일단 queue에 들어가신다. 이렇게 되면, 중간에 끼어드는 일이 없을 경우에 interval callback 실행이 끝난 뒤에 또 interval callback이 실행될 것이다. (callback의 기능에 따라서 사용자에게 나쁜 경험을 줄 수도 있을 듯)

두 번째 interval callback까지 실행이 끝나고 나면 javascript 엔진이 실행할 것이 없어 텅 빈 것을 볼 수 있다. 브라우저가 다음 비동기 이벤트를 기다리고 있다는 의미이다. 50ms에 네 번째 10ms interval이 발생하고 callback이 실행될 것이다. 이 때에는 'blocking' 요소가 없기 때문에 제 시간에 바로 실행된다. 네 번째만에 처음으로 제 시간에 실행이 된 셈.

setTimeout과 setInterval의 차이첨을 아래 예제를 통해 살펴보자.

 setTimeout(function() {
  /* Some long block of code... */
  setTimeout(arguments.callee, 10);
}, 10);

setInterval(function() {
  /* Some long block of code... */
}, 10);

두 개의 문장은 같아 보이지만 그렇지 않다. setTimeout 코드는 callback이 실행된 후 10ms 후에 다음 callback이 실행된다. 하지만 setInterval의 경우, 앞에서 설명했던 것처럼 이전 callback이 언제 실행되었는지 상관없이 매 10ms마다 callback을 실행하려고 할 것이다.

요약해봅시다!

  • javascript 엔진은 single thread이다. 비동기 이벤트는 실행 대기를 위에 queue에 쌓인다.
  • setTimeout과 setInterval은 비동기 코드의 실행 방법 자체가 다르다.
  • timer는 바로 실행되지 못할 경우 다음 실행 가능할 때까지 blocking된다(생성 당시 선언했던 delay보다 더 흐른 뒤에 callback이 실행됨).
  • interval은 delay가 없을 경우 선언해둔 지연 시간마다 실행된다.


저작자 표시 비영리 변경 금지
신고

'making web > javascript' 카테고리의 다른 글

The Call Object  (0) 2011.06.12
How Javascript Timer Work  (0) 2011.06.11
setTimeout with a shorter delay  (0) 2010.03.29
이런 잡스런... - -;  (0) 2010.01.25
Enjoying the Observer pattern with custom events  (0) 2010.01.17
Stuart Langridge: Secrets of Javascript Closures, part 1  (1) 2010.01.14


티스토리 툴바