Front-end/JavaScript

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

NiceKHJ 2024. 8. 5. 09:44

1 동기 처리 방식과 비동기 처리 방식

  • 동기 처리 방식
    동기 처리 방식은 코드가 작성된 순서대로 실행되는 방식 입니다. 자바스크립트 엔진은 단일 콜 스택을 사용하여 순차적으로 코드를 실행합니다. 즉, 한 함수가 실행되고 있는 동안에는 다른 함수가 실행될 수 없습니다.

Synchronous1이 완료될 때까지 Synchronous2는 대기 합니다.

 

 

 

  • 비동기 처리 방식
    비동기 처리 방식은 현재 실행 중인 작업이 완료되지 않아도 다음 작업을 즉시 실행할 수 있는 방식입니다.
    이는 블로킹 현상을 방지하고 애플리케이션의 반응성을 높여줍니다.

Synchronous1이 2초 동안 실행되지만 Synchronous2는 즉시 실행됩니다.

 

 

2. 자바스크립트 비동기 처리 방식

자바스크립트에서는 비동기 처리를 위한 여러 가지 방식이 있습니다.

  1. 콜백 함수 기반 비동기 처리
  2. Promise 기반 비동기 처리
  3. async / await 기반 비동기 처리

 

 

2-1 콜백 함수 기반 비동기 처리

콜백 함수는 특정 작업이 완료된 후 호출되는 함수를 의미합니다.

 

이 방식은 중첩된 콜백으로 인해 코드의 가독성이 떨어지고 콜백 지옥 현상이 발생할 수 있습니다.

 

 

2-2 Promise 기반 비동기 처리

Promise는 비동기 작업의 결과를 나타내는 객체로 작업의 성공 또는 실패를 관리할 수 있습니다.
Promise는 new Promise() 로 프로미스를 생성하고 종료될 때까지 3가지 상태를 갖습니다.

  • pending(대기) : 비동기 처리 로직이 아직 완료되지 않은 상태
  • fulfilled(이행) : 비동기 처리가 완료되어 프로미스가 결과 값을 반환해준 상태
  • rejected(실패) : 비동기 처리가 실패하거나 오류가 발생한 상태 

 

Promise를 사용하면 .then() , .catch() 메서드를 통해 비동기 작업의 결과를 쉽게 처리할 수 있습니다.

 

2-3 async / await 기반 비동기 처리

ES2017부터 도입된 async 와 await는 Promise를 기반으로 한 비동기 처리를 더 간결하게 만들어 줍니다.

async 키워드가 붙은 함수는 항상 Promise를 반환하며 await는 Promise가 처리될 때까지 기다립니다.

 

await가 실행되기 전에 다음 진행을 하지않습니다.

 

 

3. 이벤트 루프와 태스크 큐

 

 

이벤트 루프(Event Loop)

이벤트 루프는 자바스크립트 엔진의 핵심 부분으로 비동기 작업을 처리하기 위해 콜 스택과 태스크 큐를 관리합니다.

  1. 콜 스택 확인 : 이벤트 루프는 콜 스택이 비어 있는지 확인합니다. 콜 스택은 현재 실행 중인 함수의 실행 컨텍스트를 저장하는 스택입니다.
  2. 태스크 큐 확인 : 콜 스택이 비어 있으면 이벤트 루프는 태스크 큐에서 대기 중인 작업이 있는지 확인합니다. 태스크 큐는 비동기 작업의 콜백 함수들이 대기하는 큐입니다.
  3. 태스크 실행 : 태스크 큐에 대기 중인 작업이 있다면 이벤트 루프는 태스크 큐에서 가장 오래된 작업부터 콜 스택으로 이동시킵니다. 이 작업들은 콜 스택에 추가되어 실행됩니다.
  4. 반복 : 이 과정이 반복되며 이벤트 루프는 계속해서 콜 스택과 태스크 큐를 모니터링 합니다.

이벤트 루프의 작업 방식

  • 동기 작업은 콜 스택에 추가되어 즉시 실행됩니다.
  • 비동기 작업은 태스큐 큐에 추가되고 콜 스택이 비어 있을 때 이벤트 루프에 의해 실행됩니다.

 

태스크 큐 (Task Queue)

태스크 큐는 비동기 작업의 콜백 함수가 대기하는 영역입니다. 태스크 큐에는 두 가지 주요 큐가 있습니다.

 

1. 비동기 작업 큐 (Task Queue)

  • setTimeout , setInterval , setImmediate 와 같은 비동기 함수의 콜백이 이 큐에 추가됩니다.
  • 태스크 큐의 작업은 콜 스택이 비어 있을 때 순차적으로 실행됩니다.

2. 마이크로태스크 큐 (Microtask Queue)

  • Promise의 .then() , .catch() , .finally() 메서드의 콜백이 이 큐에 추가됩니다.
  • 마이크로태스크는 일반적으로 태스크 큐의 작업보다 우선적으로 실행됩니다.

 

이벤트 루프와 태스크 큐의 상호작용

  1. 동기 코드 실행 : 동기적으로 작성된 코드는 콜 스택에 추가되어 즉시 실행됩니다.
  2. 비동기 코드 실행 : 
    • 비동기 작업이 발생하면 관련된 콜백 함수는 태스크 큐에 추가됩니다.
    • Promise의 콜백 함수는 마이크로태스크 큐에 추가됩니다.
  3. 콜 스택 비우기 : 콜 스택이 비어 있을 때 이벤트 루프는 태스크 큐에서 대기 중인 작업을 콜 스택으로 이동시켜 실행합니다.
  4. 마이크로태스크 우선 처리 : 콜 스택이 비어 있을 때 이벤트 루프는 먼저 마이크로태스크 큐의 작업을 모두 처리한 후 태스크 큐의 작업을 처리합니다.

 

 

예시

이벤트 루프와 태스크 큐의 동작 방식을 보여주는 간단한 예시입니다.

 

1. start 출력

2. setTimeout 콜백은 태스크 큐에 추가

3. Promise.resolve().then 콜백은 마이크로태스크 큐에 추가

4. End 출력

5. 콜 스택이 비어 있으면 이벤트 루프는 먼저 마이크로태스크 큐의 작업을 처리합니다

6. setTimout 콜백이 태스크 큐에서 처리되어 Timeout 출력