[javascript] 비동기와 callback, 이벤트 루프

insung·2025년 4월 17일

학습자료 : https://youtu.be/rZrbQv1bMaI?si=Cli0nmDBlODjedAc

비동기 함수, 왜 필요할까? (feat. JavaScript Event Loop)

  • 자바스크립트는 싱글 스레드 언어다.
  • 이는 곧 2개 이상의 연산이나 함수를 동시에 실행할 수 없다는 의미다.
  • 하나의 연산이 실행 중이면 스레드는 block된다.

스레드 블럭

  • 컴퓨터 성능이 워낙 좋아 스레드 block을 체감하기 어려울 수 있지만, 네트워크 요청, 파일 시스템 제어, DB 쿼리 등 오래 걸리는 작업이 메인 스레드를 block하고 있다면 심각한 자원 낭비와 사용자 경험 저하로 이어진다.
  • 따라서 메인 스레드를 block하지 않고 이러한 작업들을 수행할 수 있는 방안이 필요하고, 이것이 바로 비동기 함수가 필요한 이유다.

자바스크립트 엔진과 실행 환경

  • 자바스크립트 엔진은 위와 같은 긴 시간이 소요되는 작업들을 메인 스레드에서 직접 처리하지 않는다. - fetch와 같은 웹 API를 통해 백그라운드에서 처리한다.
  • 이처럼 메인 스레드가 아닌 백그라운드에서 처리하는 작업을 비동기 작업이라고 부른다.

백그라운드는 뭘까?

  • 이를 이해하려면 자바스크립트와 자바스크립트 실행 환경을 구분해야 한다.
  • 자바스크립트 실행 환경인 Node.js와 브라우저는 자바스크립트만으로 이루어져 있지 않다.
  • 자바스크립트만으로는 프로그램의 기본적인 흐름은 잡을 수 있지만 다음과 같은 한계가 있기 때문이다.

싱글 스레드 블로킹 이슈

  • 파일 시스템 접근, OS 수준 작업이 자바스크립트만으로는 불가능
  • 이러한 한계를 극복하기 위해 자바스크립트 실행 환경 내에 자바스크립트로 접근 가능한 여러 기능들이 구현되어 있다.
  • 비동기 처리 또한 이러한 기능들 중 하나다.

콜백 함수

  • 메인 스레드에서 비동기 함수를 만나면 실제 처리는 백그라운드로 위임된다.
  • 백그라운드에서 작업이 완료되면 (성공하든 실패하든) 메인 스레드는 결과를 알아야 한다.
  • 성공했을 때 또는 실패했을 때의 처리를 해주기 위해서다.
  • 그래서 비동기 함수 호출 시 처리 완료 시 메인 스레드에서 실행할 함수를 함께 전달하는데, 이를 콜백 함수라고 한다.
  • 즉, 비동기 작업이 완료되었을 때 메인 스레드에서 실행할 함수가 콜백 함수다.
  • 콜백 함수는 메인 스레드의 메서드이다. 즉, 메인 스레드 안에서 실행되야 한다는 것.

이벤트 루프

  • 하지만 메인 스레드와 백그라운드는 별도의 프로세스이므로 콜백 함수가 언제 메인 스레드로 들어올 수 있을지 시점이 애매해질 수 있다.
  • 메인 스레드에서 다른 연산이 진행 중일 수도 있기 때문이다.
  • 따라서 콜백 함수가 들어올 시점을 정해주는 시스템이 필요하며, 이 역할을 담당하는 것이 바로 이벤트 루프다.

Call Stack, Event Queue, Event Loop

  • 메인 스레드에서 실행되는 모든 함수들은 Call Stack이라는 공간에 LIFO (Last In, First Out) 형태로 쌓인다.
    • 함수가 호출되면 콜 스택에 push되고, return 문을 만나면 pop되는 단순한 구조
  • 만약 Call Stack에 비동기 함수가 들어오면 즉시 pop되어 백그라운드로 전달된다.
    • 비동기 함수는 백그라운드에서 처리되고 있고 Call Stack에서는 다음 함수가 계속해서 실행되기 때문에 싱글 스레드 블로킹 문제를 해결할 수 있다.
    • 이후 백그라운드에서 비동기 처리가 완료되면 호출 시점에 전달한 콜백 함수가 Event Queue라는 공간에 FIFO (First In, First Out) 구조로 쌓인다.
  • 아까도 말했듯이 메인 스레드에서 실행이 되야하는 콜백 함수를 실행하려면 다시 메인 스레드의 callstack에 전달을 해줘야 하는데 이 역할을 이벤트 루프가 담당한다
    • 이벤트 루프는 이벤트 큐에서 콜 스택으로 콜백 함수를 이동시켜 주는 역할을 한다.
    • 이벤트 루프는 Call Stack이 완전히 비어있는지 수시로 확인하며, 비어있는 경우 Event Queue에서 콜백 함수를 shift한 다음 Call Stack에 push해주는 역할을 한다. (FIFO 이기 때문에 shift)

정리

요약하자면, 비동기 함수는 오래 걸리는 작업을 백그라운드로 보내 메인 스레드의 블로킹을 막고, 작업이 완료되면 콜백 함수를 통해 결과를 처리하는 방식으로 자바스크립트의 효율적인 동작을 가능하게 한다. 이때 이벤트 루프는 백그라운드 작업 완료 후 콜백 함수가 적절한 시점에 메인 스레드로 돌아와 실행될 수 있도록 관리하는 핵심적인 역할을 수행한다.

profile
안녕하세요 프론트엔드 관련 포스팅을 주로 하고 있습니다

0개의 댓글