[JS] 자바스크립트에서 비동기 코드를 실행하는 방법

JunSeok·2024년 1월 10일
0

Javascript

목록 보기
16/16

자바스크립트 런타임

  • 모든 자바스크립트 코드는 자바스크립트 런타임에서 실행된다.
  • 자바스크립트 런타임은 자바스크립트 코드를 실행하는 데 필요한 모든 부품이 포함된 컨테이너이다. 자바스크립트 런타임 정리글
  • 런타임의 핵심은 단연 자바스크립트 엔진이다. 이곳이 바로 코드가 실제로 실행되고 객체가 메모리에 저장되는 곳이다.
  • Web API는 엔진이 사용할 수 있는 API로 자바스크립트 언어와는 구별된다.
  • Callback queue는 이벤트에 부착된 모든 실행준비가 끝난 콜백함수를 갖고 있는 데이터 구조이다.
  • Event loop
    - 엔진의 call stack이 비면 이벤트 루프가 콜백큐의 첫 번째 콜백함수부터 차례대로 하나씩 콜스택에 넣어 실행한다. 이러한 작업을 event loop tick이라 한다.
    - 이벤트 루프가 자바스크립트에서 비동기 작업을 가능하게 하는 핵심 부품이다.

비동기 코드가 백그라운드에서 실행되는 방법

자바스크립트는 single threaded 언어로 한 번에 한 가지 일만 할 수 있는데, 어떻게 비동기 코드를 실행할 수 있을까?

  • DOM 관련된 모든 것은 자바스크립트 언어가 아니고 Web API의 일부이다.
  • 즉 DOM 관련 비동기 작업은 자바스크립트 엔진의 call stack이 아니라 브라우저의 Web API 환경에서 실행된다. (DOM, Timer, AJAX, fetch 호출 등)
  • 예를 들어 이미지 로딩은 call staack이 아니라 Web API 환경에서 비동기적으로 발생하고, load 이벤트가 끝나면 이벤트에 부착된 콜백함수가 콜백큐로 들어간다.
    그리고 콜스택이 빌 경우, 이벤트 루프에 의해 순서에 맞게 콜스택으로 들어가 실행된다.
  • 즉 load 이벤트에 부착된 콜백함수는 load 이벤트가 끝날 때까지 Web API 환경에 등록되어 이벤트가 끝나기를 기다리다가 이벤트가 끝나면 콜백큐에 들어간다.
  • 콜백큐의 데이터 구조는 말 그대로 큐이기 때문에 FIFO(First In First Out) 원칙을 지킨다. 그래서 가장 먼저 들어간 콜백함수가 먼저 콜스택에 들어감으로써 실행순서를 보장한다.

즉 Web API 환경과 콜백큐, 이벤트 루프를 이용하여 비동기 코드가 single threaded 환경에서도 non-blocking하게 실행될 수 있다.

Timer 사용 관련

  • Web API에서 setTimeout과 같은 timer API를 사용할 때 약간의 문제가 발생한다.
  • 시간을 5초로 설정해두었을 때, 5초 이후에 콜백함수가 무조건 실행된다고 보장할 수 없기 때문이다.
  • 타이머에 부착된 콜백함수는 5초 동안 Web API에서 대기하다가 콜백큐도 들어가는데, 콜백큐에 많은 수의 콜백함수가 대기하고 있을 경우 곧바로 실행하지 못하는 상황이 발생한다.
  • 즉 콜백함수가 5초 이후에 실행된다는 것은 보장하지만, 정확히 5초가 끝나자마자 실행된다는 것은 보장할 수 없다.

그렇다면 다른 콜백함수보다 우선순위를 높일 수 있는 promise를 사용해보자.

promise callback

  • promise 관련 콜백함수는 콜백큐에 들어가지 않는다. 대신 promise의 콜백이 들어가는 특별한 큐가 있다.
  • 이를 Microtasks Queue라 한다.
  • 이것이 특별한 이유는 콜백큐보다 높은 우선순위를 가지기 때문이다.
  • 즉 이벤트 루프는 콜백큐에 있는 콜백함수를 실행하기 전에 마이크로태스크 큐에 콜백함수가 있는지 확인하고, 있으면 마이크로태스크 큐에 있는 콜백을 모두 실행하고 정규 콜백큐로 넘어간다.

즉 promise 콜백이 다른 콜백보다 우선순위가 높다.

예시

  • 비동기 작업을 제외한 작업을 순서대로 실행하고, promise callbakc을 실행된 뒤에야 setTimeout이 실행된다.
  • 0초 타이머라고 해서 0초 이후에 바로 실행된다는 것을 보장하지 않음을 증명한다.
  • 만약 promise의 작업이 5초 이상 걸리는 작업이라면 0초 타이머라 해도 5초 이후에 실행된다.
  • 때문에 타이머로 정밀한 작업을 하려면 promisify 해서 사용하는 것이 좋다.

참조

https://dkrnfls.tistory.com/362
https://www.udemy.com/course/the-complete-javascript-course/

profile
최선을 다한다는 것은 할 수 있는 한 가장 핵심을 향한다는 것

0개의 댓글