[JavaScript] 블로킹 논블로킹, 동기 비동기

2025. 11. 6. 17:48JavaScript

728x90

이번 글에서는 JavaScript의 외부 작업 수행 간 작업 위임 및 결과 처리 방식, 싱글스레드 JS엔진이 논블로킹+비동기 작업을 처리하는 방법 및 작업의 우선순위 결정 방식에 대해 학습하고 정리한 글을 공유합니다.

  • 입출력 모델
  • 작업 완료 처리 모델
  • JS의 기반 모델
  • 싱글스레드 JS 엔진이 비동기를 처리하는 방법
  • TaskQueue, MicrotaskQueue의 실행 우선 순위
  • 회고

입출력 모델

[ 블로킹(Blocking) ]

작업 위임과 함께 제어권을 넘겨, 작업이 끝날 때 까지 스레드가 멈춰 대기하는 방식

현재 스레드의 제어권을 넘김으로써 작업의 순차적 실행이 보장되며, 제어권을 위임받은 스레드의 작업 종료까지 현재 스레드는 멈춘 상태로 대기합니다.

프로그램 실행 흐름 이해와 디버깅이 용이합니다.

 

[ 논블로킹(Non-Blocking) ]

작업 위임 시 제어권을 일시적으로 넘긴 후 돌려받고, 현재 스레드는 다른 작업을 진행하는 상태

시스템 자원의 효율적 사용 및 대기 시간 없이 병렬 처리를 수행합니다. 작업을 위임받은 스레드가 작업 종료 후, 콜백 함수나 비동기 이벤트를 통해 작업 결과를 반환합니다.


작업 완료 처리 모델

[ 동기 (Synchronous) ]

작업 위임 후, 위임한 작업의 완료 여부를 직접 확인하며 실행 순서를 보장하는 방식

작업을 위임하지만 제어권을 넘기지 않으므로, 위임한 작업의 완료 여부를 확인해야 합니다.

 

 

[ 비동기 (Asynchoronous) ]

작업 위임 후, 다른 작업을 비순차적으로 진행하는 방식

동기 방식과 마찬가지로 작업 위임 시 제어권을 넘기지 않지만, 작업 완료 여부를 위임받은 대상이 결정합니다.


JS의 기반 모델

블로킹 + 동기 방식

제어권 소유 시점이 결과 처리 순서와 동일한 방식

블로킹 방식은 작업 위임 시 현재 스레드의 제어권을 넘기고, 작업이 완료될 때 제어권을 돌려받습니다.

위임한 작업이 종료된 후, 작업 결과와 함께 제어권을 돌려받아 절차적 실행이 보장됩니다.

 

논블로킹 + 비동기 방식

제어권 소유 시점이 결과 처리 순서와 동일하지 않은 방식

논블로킹 방식은 작업 위임시 일시적으로 현재 스레드의 제어권을 넘겼다가 돌려받으므로 다른 작업을 수행할 수 있습니다.

다른 스레드에서 위임받은 작업을 처리하고, 작업 완료 시 결과를 반환합니다.

작업을 요청한 스레드는 진행 중인 다른 작업을 마친 후 반환 받은 결과에 대해 작업을 수행합니다.

주로 I/O작업 처럼, 사람의 기준에서는 빠르지만 컴퓨터 기준에서는 느린 작업 처리시 사용하는 방법으로 자원 사용량을 극대화할 수 있습니다.


싱글스레드 JS 엔진이 비동기를 처리하는 방법

JS 엔진은 한 번에 하나의 코드만 실행이 가능한 CallStack을 가집니다.

다만 JS가 실행되는 런타임 환경(웹 브라우저, nodejs)을 통해 비동기 처리가 가능합니다.

동기 작업은 CallStack에 바로 쌓아 실행하며, 비동기 작업은 대기 큐에서 대기 후 우선순위에 따라 실행합니다.

  1. 모든 동기 작업 처리 이후 비동기 작업 처리 시작
  2. setTimeout(), fetch(), dom event 등의 작업을 직접 처리하지 않고 Web API에 위임 합니다.
  3. 위임된 작업은 작업 완료 후 실행 해야 할 콜백 함수와 같은 형태로 TaskQueue에서 대기합니다.
  4. EventLoop에 의해, CallStack이 비어있는지 확인 확입합니다.
  5. TaskQueue에서 대기 중인 작업을 꺼내 CallStack에 채워넣어 결과 콜백 함수를 실행한다.
  6. 따라서 일반적으로 JS의 동기 코드들의 결과가 다 나온후, 비동기 코드들의 결과를 알 수 있다.

TaskQueue, MicrotaskQueue의 실행 우선 순위

동기 작업이 끝난 후 EventLoop는 TaskQueue보다 우선순위가 높은 MicrotaskQueue의 모든 작업을 처리 후 TaskQueue의 작업을 처리합니다.

 

[ TaskQueue(= MarcrotaskQueue) ]

일반적인 비동기 작업 대기 큐로, 아래와 같은 macro task들이 대기합니다.

  • setTimeout, setInterval 타이머 콜백함수
  • 사용자 클릭, 마우스오버의 콜백함수
  • 네트워크요청(fetch의 일부) 콜백함수

 

[ Microtask Queue ]

TaskQueue보다 빠르게 처리해야 하는 micro task들이 대기합니다.

JS 비동기 처리를 위한 Promise의 then(), catch(), finally()에 등록된 콜백함수와 같이 좀 더 빠르게 처리해야 하는 작업들이 대기하는 공간입니다.


회고

이번 학습을 통해 단순히 동기=기다린다 / 비동기=기다리지 않는다 가 아닌, 스레드 대기 여부와 작업 완료 처리 주체라는 기준을 통해 분리될 수 있다는 점을 알 수 있었다.

또한 JavaScript가 싱글 스레드임이도, 비동기 처리를 수행할 수 있는 이유가 JS엔진 자체가 아닌, 런타임 환경과 이벤트 루프에 의해 처리됨을 알 수 있었다.

특히 비동기 작업의 처리가 단순한 작업 크기에 따른 우선순위가 아니라, 코드 레벨에서 사용한 명령어에 따라 우선순위가 결정된다는 점은 이후 학습에서도 중요하다고 생각되는 포인트였다.

 

이번 학습에서 함수의 실행 흐름 제어는 “대기(Blocking) 여부”와 “완료 처리의 주체”로 구분된다는 점이 가장 인상 깊었다. 단순히 동기/비동기를 “기다림의 유무”로만 설명하는 것은 부족했고, 구조로 접근하는 것이 더 본질적이라는 걸 확인했다.

특히, 싱글 스레드 JavaScript 엔진(Call Stack)은 비동기 판별을 스스로 하지 않으며, 비동기 처리는 전적으로 런타임 환경과 이벤트 루프(Event Loop)의 조율로 가능하다는 점을 다시 정리하며 언어와 환경의 경계를 더 명확히 이해했다. 웹 API나 Node.js의 백그라운드 스레드, 그리고 큐 모델은 JS 엔진의 확장 기능이 아니라 런타임이 제공하는 비동기 실행 기반 모델이다.

 

이번 글을 쓰며 발견한 핵심은 JavaScript의 비동기 흐름에도 분명한 우선순위 레이어가 존재한다는 것이다.
Effect의 재실행 기준처럼 기본 비교가 OR 맥락으로 작동하듯, 비동기도 큐 간의 실행 우선순위가 “size(작업의 크기)” 기준이 아닌, 언어 레벨에서 선택한 API(setTimeout, Promise.then 등)에 따라 레벨이 미리 선언되는 설계 구조를 갖는다.

  • Promise의 콜백은 Microtask Queue에 등록되고, Event Loop는
    1. Call Stack(동기 코드)을 모두 비우고
    2. Microtask Queue를 완전히 drain(전부 처리)한 뒤
    3. Task Queue(Macrotask)를 처리한다.
      이것은 비동기에도 실행 우선순위와 작업 격리 전략이 내장되어 있음을 의미한다.

비동기 설계를 다음과 같이 바라보게 되었다 "매번 순수하게 동작하도록 만들 수 있는 로직은 값 일관성+side-effect free로 설계(순수 함수)하고, I/O가 필요한 부분과 비동기 제어는 작업의 urgency(긴급성/실행 타이밍 레벨)에 따라 적절한 메서드로 선택·분리해야 한다.

예를 들어:

  • 즉시 이어지는 처리 체인이 필요하면 → Promise(then) 계열을 선택
  • 일정 시간 후 실행만 보장되면 → Timer(setTimeout) 계열을 선택
  • 반복 실행의 제어가 필요하면 → setInterval 또는 스케줄러 옵션을 고려
  • DOM event 결과를 받아 후속 처리하면 → 이벤트 콜백 격리 설계를 함께 선언

이 기준은 JS 엔진이 “비동기가 필요하다”고 판단해서 큐로 보내는 것이 아니라, 개발자가 코드에서 적절한 비동기 API로 “어떤 큐 레벨에 등록할지 미리 선언한 것”이며, 그 선언의 조율을 Event Loop가 수행하는 구조다.

따라서 앞으로는
작업의 크기나 실행 시간만 보는 것이 아니라, 실행 우선순위 레벨, 의존성 관리, 그리고 참조/값의 안정성까지 고려하며 적절한 비동기 메서드를 선택함으로써 올바른 비동기 흐름 제어를 설계하겠다고 다짐했다.

728x90

'JavaScript' 카테고리의 다른 글

[JavaScript] Promise  (0) 2025.11.07
[JavaScript] Callback Function  (0) 2025.11.06
[JavaScript] First-Class Function  (0) 2025.11.05
[JavaScript] Pure Function  (0) 2025.11.05
[JavaScript] Function  (0) 2025.11.05