Promise 더 자세하게 써보기

poyal·2025년 4월 27일
1
post-thumbnail

예전부터 Promise를 잘 사용하기는 했다. 하지만 무언가 아쉬웠다. 그래서 자세히 공부해보고 더 깊게 사용하는 방법을 찾아보자.

Promise란?

promise는 기본적으로 비동기 객체입니다. 비동기로 작업을 수행하고 성공, 실패로 비동기콜백을 첨부하는 객체입니다.

기본적인 Promise 사용법

function checkCar(name?: string) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (!!name) {
        resolve(`car is ${name}`);
      } else {
        reject('name is required');
      }
    }, 1000);
  });
}

기본적인 Promise입니다. 이름을 받아서 1초후에 이름을 콜백해주는 객체입니다.

console.log('----------START-------------');
checkCar('Poyals car')
  .then((result) => {
    console.log(result);
  })
  .catch((error) => {
    console.error(error);
  });
console.log('----------END-------------');

// 결과
// ----------START-------------
// ----------END-------------
// car is Poyals car

해당 Promise를 실행하면 결과와 같이 순서대로 실행하지 않고 1초후에 then이 실행되어 출력된것을 확인할수 있다.

Promise는 생성되는 시점에서는 실행되지 않고 대리자를 반환한다. 이 대리자는 성공하거나 실패를 처리하기위한 처리기를 연결할수 있습니다. 대리자는 미래의 어떤 시점에서 처리 하겠다는 약속(Promise)를 반환한다.

상태

  • 대기(pending): 이행하지도 거부하지도 않은 초기 상태
  • 이행(fulfilled): 성공적으로 완료됨
  • 거부(rejected): 실패

Chaining

비동기 작업을 할 때는 하나씩만 사용 할 수 있지만 항상 콜백체인의 지옥에서 벗어날수 없게 됩니다.

checkCar('Poyals car').then((result) => {
  console.log(result);
  checkCar('Silvers car').then((result) => {
    console.log(result);
  });
});

예시로는 두개의 콜백체인이 있지만 만약에 5개라면? 10개라면? 길어지면 길어질수록 문제가 심각해진다. 이는 지옥의 피라미드라고도 부를수 있습니다.
promise는 promise chain으로 해결합니다.

checkCar('Poyals car')
  .then((result) => {
    console.log(result);
    return checkCar('Silvers car');
  })
  .then((result) => {
    console.log(result);
  });

콜백 체인은 없어지지 않았으나 코드는 훨신 보기 편해지는것을 볼수 있습니다.

Error Propagation

일반적인 콜백 체인 코드에서는 error핸들링도 반복적으로 등잘하게 된다.

checkCar()
  .then((result) => {
    console.log(result);
    checkCar('Silvers car')
      .then((result) => {
        console.log('result2', result);
      })
      .catch((error) => {
        console.error(error);
      });
  })
  .catch((error) => {
    console.error(error);
  });

하지만 promise chain에서는 하단의 error를 사용하여 error처리가 간단해진다.

checkCar()
  .then((result) => {
    console.log(result);
    return checkCar('Silvers car');
  })
  .then((result) => {
    console.log('result2', result);
  })
  .catch((error) => {
    console.error(error);
  });

Timing

Promise는 놀라움을 피하기 위하여 동기적으로 보이는 코드더라도 동기적으로 호출되지 않습니다. 여기에는 에러가난다 거나 코드의 문제가 생기는 문제를 피하기 위함입니다.

function carPrinter(name?: string) {
  return new Promise((resolve, reject) => {
    if (!!name) {
      resolve(`car is ${name}`);
    } else {
      reject('name is required');
    }
  });
}

carPrinter('Poyal Car').then((result) => console.log(result));
console.log('why now me?');

// 결과
// why now me?
// car is Poyal Car

즉시 실행되는 대신에 전달된 promis 객체는 마이크로 테스크 대기열에 저장되고, 해당 테스크가 끝나는 즉시 실행됩니다.

동시성

Promise는 기본적으로 비동기 작업이기 때문에 작업들의 동시성을 지키기가 힘들다. 동시성을 확보하면서도 병렬작업을 하기위한 여러가지 기능들이 존재한다. 각각의 기능들은 내용이 Promise 만큼 방대하기 때문에 소개만하고 지나간다.

Promise.all()

모든 프로미스가 이행되면 이행되고, 프로미스 중 하나라도 거부되면 거부됩니다.

Promise.allSettled()

모든 프로미스가 해결되면 이행됩니다.

Promise.any()

프로미스 중 하나라도 이행되면 이행하고, 모든 프로미스가 거부되면 거부합니다.

Promise.race()

프로미스 중 하나라도 해결되면 해결됩니다. 즉, 프로미스 중 하나라도 이행되면 이행되고, 약속 중 하나라도 거부되면 거부됩니다.

참조

0개의 댓글