250228 TIL #621 JavaScript 비동기 프로그래밍

김춘복·2025년 2월 28일
0

TIL : Today I Learned

목록 보기
624/627

Today I Learned

오늘은 JS에서 핵심 개념인 비동기 프로그래밍에 대해 정리해봤다.


JavaScript 비동기 프로그래밍


이미지 출처 : bandal

동기식 프로그래밍

코드가 순차적으로 실행되며, 각 작업이 완료될 때까지 다음 작업이 대기하는 방식

console.log(1);
console.log(2);
console.log(3);

비동기식 프로그래밍

작업이 완료될 때까지 기다리지 않고 다음 코드를 실행하는 방식.

  • 시간이 오래걸리는 작업(네트워크 요청, 파일 I/O 등)을 처리할 때 유용
console.log("시작");
setTimeout(() => {
  console.log("비동기 작업 완료");
}, 2000);
console.log("종료");
시작
종료
비동기작업완료

JS의 단일 스레드 특성

  • JS는 기본적으로 단일스레드 언어다. 다중스레드를 지원하는 자바와는 다르게 한 번에 하나의 작업만 처리할 수 있다.

  • JS는 단일스레드지만 비동기 프로그래밍을 통해 동시성을 구현한다.
    Event Loop(이벤트 루프)라는 매커니즘을 사용해 비동기 작업을 관리한다.


비동기 프로그래밍 발전 과정

1. 콜백 함수(Callbacks)

가장 초기의 비동기 처리 방식

  • 다른 함수에 인자로 전달되어 해당 함수의 실행이 완료된 후 호출되는 함수
function fetchData(url, callback) {
  // 비동기 작업 시뮬레이션
  setTimeout(() => {
    const data = { message: "데이터 가져오기 성공" };
    callback(data);
  }, 1000);

}

fetchData("test.com/api", (data) => {
  console.log(data.message); // 데이터 가져오기 성공 출력
});
  • 여러 비동기 작업을 순차적으로 처리할 때 콜백함수가 중첩되어 코드의 가독성이 떨어지는 현상을 콜백 지옥이라고 한다.

2. 프로미스(Promises)

비동기 작업의 최종 완료(or 실패)와 그 결과값을 나타내는 객체.

  • 콜백지옥을 해결하고 더 구조화된 방식으로 비동기 코드를 작성할 수 있게 함
function fetchData(url) {
  return new Promise((resolve, reject) => {
  // 비동기 작업 시뮬레이션
    setTimeout(() => {
      const data = { message: "데이터 가져오기 성공" };
      resolve(data); // 성공시 resolve 호출
    }, 1000);
  });
}

fetchData("test.com/api")
  .then(data => console.log(data.message))
  .catch(error => console.error(error));

프로미스 체이닝

여러 비동기작업을 순차적으로 처리할 수 있음

fetchData("test.com/api")
  .then(data => {
    console.log(data.message);
    return fetchData("test.com/api2"); // 새로운 프로미스 반환
  })
  .then(newData => {
    console.log(newData.message);
  })
  .catch(error => console.error(error));

3. Async/Await

ES2017에서 도입된 프로미스 기반의 코드 스타일로 더 동기적인 스타일로 비동기 작업 처리.
가독성이 크게 향상됨

  • async는 함수가 프로미스를 반환하도록 함
  • await은 프로미스가 해결될 때까지 함수 실행 일시 중지
  • try/catch 구문으로 오류 처리 가능
  • 동기식 코드처럼 보이지만 실제로는 비동기적으로 작동
async function fetchDataAsync(url) {
  try {
    // await은 프로미스가 해결될 때까지 함수 실행 일시 중지
    const response = await fetch(url);
    const data = await response.json();
    console.log(data);
    return data;
  } catch (error) {
    console.error(error);
  }
}

fetchDataAsync("test.com/api");
  • 여러 비동기 작업 순차적 처리
// 여러 비동기 작업을 순차적으로 처리
async function processData() {
  try {
    const data1 = await fetchDataAsync("example.com/api1");
    const data2 = await fetchDataAsync("example.com/api2");
    const data3 = await fetchDataAsync("example.com/api3");
    
    console.log("모든 데이터 처리 완료:", data1, data2, data3);
  } catch (error) {
    console.error("데이터 처리 중 오류 발생:", error);
  }
}

이벤트 루프(Event Loop)

JS의 비동기 작업 처리는 이벤트루프를 통해 이뤄진다.
이벤트루프는 JS 엔진이 비동기 작업을 관리하는 방식이다.

  • 콜스택(Call Stack) : 현재 실행중인 함수를 추적
  • 태스크 큐(Task Queue) : setTimeout, setInterval 등의 비동기 작업이 완료된 후 실행될 콜백함수가 대기
  • 마이크로태스크 큐(Microtask Queue) : 프로미스의 then/catch/finally 핸들러가 대기
  • 이벤트 루프 : 콜스택이 비어있을 때 마이크로태스크 큐, 태스크 큐 순으로 작업을 콜스택으로 이동시킴
console.log("1"); // 동기 작업

setTimeout(() => {
  console.log("2"); // 매크로태스크
}, 0);

Promise.resolve().then(() => {
  console.log("3"); // 마이크로태스크
});

console.log("4"); // 동기 작업

// 1 4 3 2 순서로 출력
// 동기작업-마이크로태스크-매크로태스크 순으로 실행
profile
Backend Dev / Data Engineer

0개의 댓글

관련 채용 정보