모던자바스크립트, 비동기프로그래밍

Edwin·2023년 2월 23일
0
post-thumbnail
  • 본 포스트은 모던자바스크립트 Deep Dive 제 42장을 기반으로 정리했습니다.
  • 본 포스티는 다크모드에 최적화 되어 있습니다.

비동기 프로그래밍

01 동기처리

콜스택에 푸시가 되어 최상단에 놓여진다는 것은 함수가 실행되었다는 것을ㄷ 뜻한다. 이때 이전에 실행되고 있던 실행 컨텍스트들은 중단되게 된다. 왜냐하면 자바스크립트 엔진은 단 하나의 실행 컨텍스트 스택을 가지고 있기 때문이다. 즉 창구가 하나이기에 동시에 2개 이상의 함수를 실행할 수 없다는 것이다. 최상위 요소에서 "실행 중인 실행 컨텍스트"를 제외한 모든 실행 컨텍스트는 모두 실행 대기 중인 태스크(task)가 된다. 이후 최상위 실행 컨텍스트가 팝되어 스택에서 제거되면, 비로서 그때가서야 중단되었던 작업을 이어가기 시작한다.

const x =1;
function one() {
 two()
}
function two() {}

one()
console.log(x)

1) 위의 코드의 실행컨텍스를 읽어보자.

    1. 전역 실행컨텍스트가 실행
    1. 진행되다가 만난 one() 함수호출에 따라서 전역 실행컨텍스트는 중단되고 one() 실행컨텍스트가 실행
    1. one() 실행컨텍스트에서 만난 two()에서 one() 실행컨텍스트가 중단되고, two()실행컨텍스트가 실행
    1. two()실행컨텍스트가 완료된 후에 팝되어 스택에서 제거, one() 실행컨텍스트 재개
    1. one() 실행컨텍스트가 완료된 후에 팝되어 스택에서 제거, 전역 실행컨텍스트가 실행 후 종료

2) 실행컨텍스트와 싱글스레드

실행컨텍스트가 위와 같은 방식으로 동작하는 이유는 자바스크립트 엔진이 싱글 스레드 이기 때문이다. 여기서 싱글 스레드란 한 번에 하나의 태스크만 실행하는 일처리 방식을 말한다. 여기서 태스크란 실행 컨텍스트로 올라오는 각개의 실행컨텍스트들을 말한다.

만약 하나의 태스크를 처리하는 과정에서 오랜 시간이 걸리면, 자바스크립트 엔진은 다른 태스크들을 블로깅(작업중단)을 선언한다. 작업이 중단된 태스크들은 콜스택의 최상단에 있는 실행컨텍스트가 제거되면 순차적으로 콜스택의 위에서 아래로 순차적으로 실행된다.

위의 예에서 말하면, two()실행컨텍스트가 실행되는 동안 one() 실행컨텍스트와 전역 실행컨텍스트는 중단된다.

싱글스레드 아래서의 동기 처리 방식의 한계

동기처리방식은 태스크를 순서대로 하나씩 처리하므로 실행 순거는 보장되지만, 해당 태스크의 실행이 종료될 때까지 나머지 태스크들의 실행이 중단(블로킹) 된다는 단점이 있다.

3) 비동기처리

비동기처리란? 동기처리에서 발생되는 작업중단의 시간을 오롯이 기다리는 것이 아니라, 현재 실행 중인 태스크가 종료되지 않은 상태라도 다음 태스크를 곧바로 실행하는 방식을 말한다.

function one() {
	console.log('one');
}

function two() {
	console.log('two');
}

setTimeout(foo, 3*1000);
bar()

이는 동기처리 방식을 극복한다. 이를 위해 등장한 개념이 비동기 함수인데, 전통적으로 비동기 함수는 콜백 패턴을 사용한다. 그러나 비동기 처리가 장점만 가진 것은 아닌데, 비동기 처리를 위한 콜백패턴은 콜백 헬을 발생시켜 가독성을 나쁘게 할 뿐 아니라, 비동기 처리 중 발생된 에러의 처리를 어렵게 만들고, 여러 개를 동시에 처리하는데 어려움을 가지고 있다는 한계가 있기에, 프로미스라는 개념이 등장하였다.

비동기 처리 방식의 사례

  • 타이머 함수인 setTimeout
  • 타이머 함수인 setInterval
  • HTTP 요청
  • 이벤트 핸들러

4) 이벤트 루프와 태스크 큐

비동기 처리를 이해하기 위해서는 이벤트 루프와 태스크 큐와 깊은 관계가 있다. 먼저 이벤트 루프(event loop)란 HTML요소가 애니메이션 효과를 통해 움직이면서 이벤트를 처리하기도 하고, HTTP 요청을 통해 서버로부터 데이터를 가지고 오면서 렌더링을 동시에 동작하는 자바스크립트의 동시성을 지칭하는 용어이다. 그러나 이벤트 루프 자체는 브라우저에 내장되어 있는 기능이기에 별도의 것이 아니라는 것을 먼저 기억하고 넘어가야 한다.

기본적인 자바스크립트 엔진의 작동방식은

  • 먼저, 함수호출이되면 실행컨텍스트가 실행되며 콜스택에 들어간다.
  • 그리고 순서대로 콜스택의 과정에 푸시되고 팝되며 실행된다.

그런데 만약 비동기적 처리 작동방식이 존재한다면 어떻게 될까?

  • 태스크큐 : 비동기 함수의 콜백 함수 또는 이벤트 핸들러가 일시적으로 보관되는 영역이다.
  • 이벤트루프 : 이벤트루프는 콜 스택에 현재 실행 중인 실행 컨텍스트가 있는지, 그리고 태스크 큐에 대기 중인 함수가 있는지 반복해서 확인하며, 만약 콜 스택이 비어 있고 태스크큐에서 대기 중인 함수가 있다면 이벤트 루프는 순차적으로 태스크 큐에 대기 중인 함수를 콜 스택으로 이동시킨다.

이러한 동작 방식으로 싱글 스레드이지만, 비동기적 동작을 가능하게 만드는 것이 비동기 처리 방식의 사례이다. 약간의 우회적인 방법으로 멀티스레드인 브라우저의 기능을 빌려 콜스택의 상황에서 자바스크립트 엔진은 콜백함수를 태스크큐라는 별도의 공간으로 보내고, 그리고 이 둘 사이에서 눈치보며 동작이 진행되도록 동작하는 녀석이 이벤트루프인 셈이다.

5) 정리하면

비동기 함수인 setTimeout의 콜백 함수는 태스크 큐에 푸시되어 대기하다가 콜 스택이 비게 되면, 다시 말해 전역 코드 및 명시적으로 호출된 함수가 종료되면 비로소 콜 스택에 푸시되어 실행된다. 이 과정에서 타이머함수로 지정된 시간보다 약간 더 늦게 동작할 수 있다. 왜냐하면 눈치보면서 기다려야 하기 때문이다.

이러한 동작이 가능한 것은 위에서 간략하게 말한 브라우저의 기능 때문이다. 브라우저는 자바스크립트 엔진 이외에도 렌더린 엔진과 WEB API를 제공하며, WEB API는 DOM API와 타이머 함수, HTTP 요청(Ajax)과 같은 비동기 처리를 포함한다. 이러한 환경에서 setTimeout 함수의 타이머 설정과 만료시 콜백함수를 태스크 큐에 등록하는 처리방식이 전개되는 것이다. 자바스크립트 엔진에서 처리하는 것이 아니다.

그 결과 브라우저와 자바스크립트가 병행 처리가 이뤄지기에, 비동기적 방식이 가능한 것이다.

profile
신학전공자의 개발자 도전기!!

0개의 댓글