자바스크립트 이벤트 루프

y0ung·2020년 12월 15일
0

자바스크립트는 싱글스레이드이면서 비동기처리도 가능한데, 자바스크립트 언어의 비동기 행위들은 엄밀히 말하면 자바스크립트 언어 그 자체의 일부는 아니다. 오히려 비동기 행위는 브라우저 내부(혹은 프로그래밍 환경)에 존재하는 자바스크립트 언어의 핵심단의 상위에 만들어졌다. 또한 브라우저의 API를 통해 접근한다.

기본 구조

  • heap : 객체는 메모리에서 대규모이면서 대부분 구조화 되지 않은 메모리 영역인 힙영역내부에 할당된다.
  • stack : 자바스크립트 코드 실행을 위해 제공된 싱글 스레드를 나타낸다. 함수 호출은 frame의 스택을 구성한다.
  • browser | web API : 브라우저와 웹 API는 웹 브라우저 내부에 구성되며 브라우저로 혹은 주변 컴퓨터 환경으로부터 데이터를 노출시킬수 있고 이것들을 통해 유용하지만 복잡한 것들도 사용할수 있다. 이러한것들은 자바스크립트 언어 그 자체는 아니고 오히려 자바스크립트 언어 코어 단의 상위에 만들어져, 자바스크립트 코드 사용시에 추가적인 능력을 제공한다. 예를 들면 Geolocation API 는 지역 데이터를 가져오기위한 간단한 자브스크립트 구조를 제공한다. 위치 데이터를 불러오고 코드에서 사용할 수 있도록 브라우저 환경에 이것을 반환한다. 하지만 이러한 복잡성은 다시 API에 의해 추상화됬다.

예제1

function main() {
  console.log('A');
  setTimeout(
    function display() { console.log('B'); }
  , 0);
  console.log('C');
}

main();

// 출력
// A
// C
// B

'A','C'를 콘솔에 로깅하는 2개의 console.log를 가진 main함수이다. 그리고 그사이 'B'를 로깅하는 0ms의 딜레이를 가진 setTimeout()함수를 호출한다.

코드 실행중 내부에서 일어나는 일들

  1. 메인 함수 호출 -> 프레임으로 stack에 push → 브라우저 첫번째 statement(console.log('A'))를 stack에 넣음 → 해당 프레임은 stack에서 pop된다.→ 'A' 콜솔에 표기.

  2. 두번째 statement(콜백display() 과 함께 0ms의 딜레이를 가진 setTimeout() ) 가 콜스택으로 push → setTimeout() 함수는 제공된 콜백을 딜레이하기 위해 브라우저 API를 사용 → 타이머를 돌리기위해 콜백이 브라우저로 넘어가면 setTimeout()을 가진 프레임은 pop

  3. 브라우저에 display() 실행을 위한 타이머가 돌아가는 도중 console.log('C')가 콜스택에 push (제공된 딜레이는 0ms 였기 때문에, 콜백은 브라우저가 콜백을 받자마자 메시지 큐에 바로 추가)

  4. 마지막 statement의 실행 후 main() 프레임은 콜스텍 밖으로 pop → 콜스택은 빈(empty)가 된다. 브라우저가 어떤 메시지를 큐에서 콜스택으로 push하기 위해서는 먼저 콜스택을 반드시 비워야 한다. setTimeout()의 딜레이가 0초임에도 불구 하고, display()으로의 콜백이 콜스택에 존재했던 모든 프레임이 실행될 때까지 기다려야 했던 이유이다.

  5. 콜백 display()가 콜스텍에 push된후 실행 → 'C' 가 콘솔에 나타남.

  • 위의 모든 과정이 자바스크립트의 이벤트 루프이다.
  • setTimeout(function, delayTime)에 들어가는 delay 파라미터는 어떤 함수가 실행된 뒤의 정확한 시간 딜레이를 말하는 것이 아닌, 함수가 실행됐을 때의 어떤 지점이후의 최소 대기시간을 의미한다.

예제2 _ 심화

function main() {
  console.log('A');
  setTimeout(
    function exec() { console.log('B'); }
  , 0);
  runWhileLoopForNSeconds(3);
  console.log('C');
}

main();

function runWhileLoopForNSeconds(sec) {
  let start = Date.now(), now = start;
  while (now - start < (sec*1000)) {
    now = Date.now();  
  }
}

// Output
// A
// C
// B

  • runWhileLoopForNSeconds()는 함수가 호출된 시간에서 경과된 시간을 걔속 측정하여 경과된 시간이 함수의 인자로 받은 시간과 일치한지 계속해서 검증한다. while반복문이 콜스택에서 상주하면서 브라우저 API를 사용하지 못하게 하는 blocking statement 이다. 이 함수는 실행이 끝날 때까지 뒤에 오는 모든 statements들이 실행되지 못하게 막는다.

  • 위의 코드에서, setTimeout()은 0초의 딜레이를 가지고 shile반복문은 3초간 실행되더라도, exec()콜백은 메시지 큐에 갇혀 있다. while 반복문은 3초가 지날 때 까지 콜스택 위에서 계속 실행된다. (jsavscript의 엔진은 싱글스레이드이기때문) 3초가 지나 콜스택이 비게 되는 순간 exec()콜백은 콜스택으로 들어와서 실행된다.

setTimeout()의 딜레이 인자는 실행이 시작되는 타이밍을 보장해주는 것이 아니다. 최소한 얼마정도는 있다가 실행되라 정도의 의미로 생각 하는 것이 좋다.


참고

profile
어제보다는 오늘 더 나은

0개의 댓글