관리 메뉴

진취적 삶

42 비동기 프로그래밍 본문

개발 도서/자바스크립트 deepdive

42 비동기 프로그래밍

hp0724 2023. 7. 13. 12:00

42.1 동기처리와 비동기 처리

함수를 호출하면 함수 코드가 평가되어 함수 실행 컨텍스트가 생성된다.

생성된 함수 실행 컨텍스트는 실행 컨텍스트 스택에 푸시되고 함수 코드가 실행된다.

실행 컨텍스트 스택에 함수 실행 컨텍스트가 푸쉬되는것은 바로 함수 실행의 시작을 의미한다.

js 엔진은 단 하나의 실행 컨텍스트 스택을 갖는다.

대기중인 task 들은 현재 실행중인 실행 컨텍스트가 pop 되어 실행 컨텍스트 스택에서 제거되면,

비로소 실행되기 시작한다.

한번에 하나만 실행 할수 있는 싱글 스레드 방식으로 동작한다.

시간이 걸리는 테스크를 실행하는 경우 블로킹이 발생한다.

//sleep 함수는 일정시간이 경과한 이후에 콜백함수를 호출한다. 
function sleep(func, delay) {
  const delayUntil = Date.now() + delay;

  while (Date.now() < delayUntil);
  func();
}

function foo() {
  console.log("foo");
}
function bar() {
  console.log("bar");
}
//sleep 함수는 3초 이상 실행
sleep(foo, 3000);
//bar 함수는 sleep 함수의 실행이 종료된 이후에 호출되므로 3초이상블로킹 
bar();

현재 실행중인 task 가 종료할 때까지 다음에 실행될 테스크가 대기하는 방식을 동기 처리라고 한다.

동기 처리 방식은 테스크를 순서대로 하나씩 처리하므로 실행순서가 보장

하지만 테스크가 종료할때까지 이후 테스크들이 blocking 되는 단점

function foo() {
  console.log("foo");
}
function bar() {
  console.log("bar");
}
//타이머 함수 setTimeout 은 일정 시간이 경과한 이후에 callback 함수 foo를 호출
//타이머 함수 setTimeout 은 bar함수를 blocking 하지 않는다 .
setTimeout(foo, 3 * 1000);
bar();

현재 실행중인 테스크가 종료되지 않은 상태라 해도 다음 태스크를 곧바로 실행하는 방식을 비동기 처리라고 한다.

현재 실행중인 태스크가 종료되지 않은 상태라 해도 다음 태스크를 곧바로 실행하므로 블로킹이 발생하지 않는다.

단점은 태스크의 실행 순서가 보장되지 않는다.

타이머 함수인 setTimeout, setInterval ,HTTP 요청 ,이벤트 핸들러는 비동기 처리 방식으로 동작

42.2 이벤트 루프와 태스크 큐

JS는 동시성의 지원하는 것이 바로 이벤트 루프이다 .

이벤트 루프는 브라우저에 내장되어있는 기능중 하나

JS 엔진은 2개의 영역으로 구분가능

  • 콜 스택 (call stack ) 소스코드 평가 과정에서 생성된 실행 컨텍스트가 추가되고 제거되는 스택 자료구조인 실행 컨텍스트 스택이 바로 콜 스택이다 .

함수를 호출하면 함수 실행 컨텍스트가 순차적으로 콜 스택에 푸시되어 순차적으로 실행된다. js 엔진은 단 하나의 콜스택을 사용하기 때문에 최상위 실행 컨텍스트가 종료되어 제거되기 전까지는 다른 어떤 태스크도 실행하지 않는다 .

  • 힙 (heap) 힙은 객체가 저장되는 메모리 공간이다 . 콜 스택의 요소인 실행 컨텍스트는 힙에 저장된 객체를 참조한다. 객체가 저장되는 메모리 공간인 힙은 구조화 되어 있지 않다는 특징이 있다. 객체는 원시값과 달리 크기가 정해져 있지 않음

브라우저 환경은 태스크 큐와 이벤트 루프를 제공한다

  • 태스크 큐 setTimeout 과 setInterval 같은 비동기 함수의 콜백 함수 또는 이벤트 핸들러가 일시적을 보관되는 영역.
  • 이벤트 루프 콜 스택에 현재 실행중인 실행 컨텍스트가 있는지 ,테스크 큐에 대기중인 함수가 있는지 반복해서 확인한다. 만약 콜스택이 비어있고 태스크 큐에 대기중인 함수가 있다면 이벤트 루프는 순차적(FIFO)으로 태스크 큐에 대기중인 함수를 콜 스택을 이동시킨다.
function foo() {
  console.log("foo");
}
function bar() {
  console.log("bar");
}
//타이머 함수 setTimeout 은 일정 시간이 경과한 이후에 callback 함수 foo를 호출
//타이머 함수 setTimeout 은 bar함수를 blocking 하지 않는다 .
setTimeout(foo, 0);
bar();

//BAR FOO
  1. 전역 코드가 평가되어 전역 실행 컨텍스트가 생성되고 콜스택에 PUSH
  2. 전역 코드가 실행되기 시작하여 setTimeout 함수가 호출 setTimeout 함수의 함수 실행 컨텍스트가 생성되고 콜스택에 push 되어 현재 실행 중인 실행 컨텍스트가 된다.
  3. setTimeout 함수가 실행되면 콜백 함수를 호출 스케줄링하고 종료되어 콜 스택에서 pop 된다. 호출 스케줄링 , 즉 타이머 설정과 타이머가 만료되면 콜백함수를 테스크 큐에 푸시하는것은 브라우저 역할
  4. 브라우저가 수행 하는 4-1 과 js 엔진이 수행하는 4-2는 병행 처리
    1. 브라우저는 타이머를 설정하고 타이머의 만료를 기달린다. 타이머 만료되면 foo가 태스크 큐에 push 된다. 지연시간이 0이지만 4ms 이하인 경우 최소 지연시간 4ms가 지정된다. 즉 4ms 후에 콜백 함수 foo 가 테스크 큐에 push 되어 대기하게 된다.
    2. bar 함수가 호출되어 bar 함수의 실행 컨텍스트가 생성되고 콜 스택에 push 되어 현재 실행중인 컨텍스트가 된다. bar 함수가 종료되어 콜스택에서 pop 된다. 이때 브라우저가 설정한 4ms 가 경과했다면 foo 함수는 아직 태스크 큐에서 대기중이다.
  5. 전역 코드 실행이 종료되고 전역 실행 컨텍스트가 콜 스택에서 pop 된다. 콜 스택에는 아무런 실행 컨텍스트도 존재하지 않게 된다.
  6. 이벤트 루프에 의해 콜 스택에 비어있음이 감지괴고 테스크 큐에서 대기중인 콜백함수 foo 가 이벤트 루프에 의해 콜 스택에 push된다. 콜스택에 push 되어 현재 실행중인 실행 컨텍스트가 되고 foo 함수가 종료되어 콜 stack 에서 pop 된다.

js는 싱글 스레드로 동작한다. 싱글 스레드 방식으로 동작하는것은 브라우저가 아니라 브라우저에 내장된 js 엔진이라는것에 주의하기바란다 . 모든 js 코드가 자바스크립트 엔진에서 싱글 스레드 방식으로 동작한다면 js는 비동기로 동작할수 없다. 즉 js 엔진은 싱글 스레드로 동작하지만 브라우저는 멀티 스레드로 동작한다.

'개발 도서 > 자바스크립트 deepdive' 카테고리의 다른 글

40 이벤트  (0) 2023.07.13
41 타이머  (0) 2023.07.13
43 Ajax  (0) 2023.07.13
44 REST API  (0) 2023.07.13
45 프로미스  (0) 2023.07.13