[JavaScript] 8. 비동기 프로그래밍

BANG·2025년 8월 22일

JS

목록 보기
8/8

비동기 프로그래밍

  • 작업이 완료될 때까지 기다리지 않고 잠재적으로 오래 실행되는 작업을 시작하여 해당 작업이 실행되는 동안에도 다른 이벤트에 응답할 수 있게 하는 기술
  • JavaScript는 본질적으로 단일 스레드
  • 병렬화가 없고, 동시성만 가능
  • 비동기 프로그래밍은 이벤트 루프에 의해 구동
    - 일련의 작업을 대기하고 완료를 위해 폴링(polling)할 수 있음
  • 외부 환경과 상호작용을 할 때 중요
  • 오래 실행되는 작업을 비동기식으로 유지하면, 이 프로세스가 대기하는 동안 다른 프로세스가 계속 실행될 수 있음
  • 비동기 값이 있는 경우, 해당 값을 동기적으로 가져올 수 없음

비동기 코드를 작성하는 세 가지의 관용적인 방법

  • 콜백 기반 방법
  • Promise 기반 방법
  • Promise의 문법적인 설탕(syntactic sugar)인 async/await 방법

이벤트 처리기

  • 이벤트 처리기는 실제로 비동기 프로그래밍의 한 형태
  • 이벤트가 발생할 때마다 호출되는 함수(이벤트 처리기)를 제공하는 것
  • "이벤트"가 "비동기 작업 완료"인 경우, 이 이벤트를 사용하여 호출자에게 비동기 함수 호출의 결과를 알릴 수 있음

    이벤트(비동기 작업 완료)가 발생할 때마다 호출되는 함수


콜백

  • 이벤트 핸들러는 콜백의 특정 유형
  • 적절한 시점에 호출될 것으로 예상하여 다른 함수로 전달되는 함수
  • 대부분의 최신 비동기 API는 콜백을 사용하지 않음
    - "콜백 지옥(callback hell)" 또는 "파라미드 오브 둠(pyramid of doom)" 때문
function downloadFile(url, callback) {
  console.log("Downloading file from", url);
  // 가상의 다운로드 완료 후 호출
  setTimeout(() => {
    console.log("Download complete.");
    callback(); // 여기서 콜백 실행
  }, 2000);
}

downloadFile("https://example.com", function () {
  console.log("After download: processing file...");
});

Promise

  • Promise 객체는 비동기 작업이 맞이할 미래의 완료 또는 실패와 그 결과 값을 나타냄
  • 비동기 작업의 최종 완료 또는 실패를 나타내는 객체
  • promise는 함수에 콜백을 전달하는 대신에, 콜백을 첨부하는 방식의 객체
createAudioFileAsync(audioSettings).then(successCallback, failureCallback);

//=====================

const promise = createAudioFileAsync(audioSettings);
promise.then(successCallback, failureCallback);
  • 콜백은 JavaScript Event Loop가 현재 실행중인 콜 스택을 완료하기 이전에는 절대 호출되지 않음

  • 비동기 작업이 성공하거나 실패한 뒤에 then() 을 이용하여 추가한 콜백도 같음

  • then()을 여러번 사용하여 여러개의 콜백을 추가 할 수 있음
    - 각각의 콜백은 주어진 순서대로 하나 하나 실행되게 됨

  • 두 개 이상의 비동기 작업을 순차적으로 실행해야 하는 상황
    - 순차적으로 각각의 작업이 이전 단계 비동기 작업이 성공하고 나서 그 결과값을 이용하여 다음 비동기 작업을 실행해야 하는 경우
    - promise chain을 이용하여 해결

  • Promise는 다음 중 하나의 상태를 가짐
    - 대기(pending): 이행하지도, 거부하지도 않은 초기 상태
    - 이행(fulfilled): 연산이 성공적으로 완료
    - 거부(rejected): 연산이 실패

  • 이행이나 거부될 때, 프로미스의 then 메서드에 의해 대기열(큐)에 추가된 처리기들이 호출

  • .then() 메서드는 최대 두 개의 인수를 받음
    - 첫 번째 인수는 프로미스의 이행된 경우에 대한 콜백 함수
    - 두 번째 인수는 거부된 경우에 대한 콜백 함수

  • then() 함수는 새로운 promise를 반환

  • then 에 넘겨지는 인자는 선택적(optional)

  • .then()에 프로미스 객체를 반환하는 콜백 함수가 없는 경우에도 처리는 체인의 다음 링크까지 계속됨
    - 체인은 마지막 .catch()까지 모든 거부 콜백 함수를 안전하게 생략할 수 있음

doSomething()
  .then(function (result) {
    return doSomethingElse(result);
  })
  .then(function (newResult) {
    return doThirdThing(newResult);
  })
  .then(function (finalResult) {
    console.log("Got the final result: " + finalResult);
  })
  .catch(failureCallback) // then(null, failureCallback) 의 축약
;

// ===================================

doSomething()
  .then((result) => doSomethingElse(result))
  .then((newResult) => doThirdThing(newResult))
  .then((finalResult) => {
    console.log(`Got the final result: ${finalResult}`);
  })
  .catch(failureCallback);
  • Promise 는 프로미스가 생성된 시점에는 알려지지 않았을 수도 있는 값을 위한 대리자
  • 비동기 연산이 종료된 이후에 결과 값과 실패 사유를 처리하기 위한 처리기를 연결할 수 있음
  • 프로미스를 사용하면 비동기 메서드에서 마치 동기 메서드처럼 값을 반환할 수 있음
  • 최종 결과를 반환하는 것이 아니고, 미래의 어떤 시점에 결과를 제공하겠다는 '프로미스(promise)'를 반환
  • resolve, reject는 함수 매개변수 -> 다른 이름 사용 가능
function fetchData1() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const success = true; // 이걸 false로 바꾸면 에러 처리됨
      if (success) {
        resolve("데이터 가져오기 성공!");
      } else {
        reject("실패했어요!");
      }
    }, 2000);
  });
}

function fetchData2() {
  const promise = new Promise((resolve, reject) => {
    console.log("데이터 가져오는 중...");

    setTimeout(() => {
      const success = true;

      if (success) {
        resolve("✅ 데이터 가져오기 성공");
      } else {
        reject("❌ 데이터 가져오기 실패");
      }
    }, 2000);
  });

  return promise;  // <- Promise 객체 반환
}



fetchData1()
  .then((result) => {
    console.log("성공:", result);
  })
  .catch((error) => {
    console.error("실패:", error);
  });

const myPromise = fetchData2();  // 여기서 아직 결과 없음 (대기 상태)

myPromise
  .then((result) => {
    console.log("받은 결과:", result);
  })
  .catch((err) => {
    console.error("에러 발생:", err);
  });

async/await

  • async 함수가 무조건 Promise를 반환하게 만듦
  • await는 Promise가 끝날 때까지 잠깐 멈춤, 끝나면 결과를 변수로 받음
async function 함수이름() {
  const result = await 비동기함수(); // 끝날 때까지 기다림
}
  • await은 "기다려서 결과 받아오는 키워드", async는 그런 코드를 쓸 수 있게 하는 함수 선언
async function getUser() {
  try {
    const response = await fetch("https://jsonplaceholder.typicode.com/users/1");
    const user = await response.json(); // JSON 파싱도 await 필요
    console.log("사용자 이름:", user.name);
  } catch (err) {
    console.error("에러 발생:", err);
  }
}

getUser();

Promises

  • 이전 작업이 완료될 때 까지 다음 작업을 연기 시키거나, 작업실패를 대응할 수 있는 비교적 새로운 JavaScript 기능
  • Promise는 비동기 작업 순서가 정확하게 작동되게 도움을 줌
profile
Record Everything!!

0개의 댓글