[Study/Web] Promise 객체 생성하기

SoShy·2024년 1월 31일
0

웹 개발

목록 보기
16/21
post-thumbnail

1. Promise 객체 생성하기


promise 객체를 직접 생성하기 위한 기본 코드는 다음과 같다.

const p = new Promise((resolve, reject) => {

});

위 코드에서, promise 객체 내 작성된 함수는 객체가 생성될 때 자동으로 실행되는 executor 함수이다.

resolve 파라미터에는 생성될 promise 객체를 fulfilled 상태로 만들 수 있는 함수가 연결되며,

reject 파라미터에는 생성될 promise 객체를 rejected 상태로 만들 수 있는 함수가 연결된다.

아래 예시 코드의 경우, p라는 promise 객체가 2초 후에 fulfilled 상태가 되며, 그 때 resolve 함수 안에 넣은 success라는 문자열이 작업 성공 결과가 되고, 결과적으로 success라는 문자열이 출력된다.

const p = new Promise((resolve, reject) => {
  setTimeout(() => {resolve('success');}, 2000);
});

p.then((result) => {console.log(result);});

반면, 아래 예시 코드의 경우, p라는 promise 객체가 2초 후에 rejected 상태가 되며, 그 때 reject 함수 안에 넣은 fail이라는 문자열이 작업 실패 결과가 되고, 결과적으로 fail이라는 메세지를 가진 에러 객체가 출력된다.

const p = new Promise((resolve, reject) => {
  setTimeout(() => { reject(new Error('fail')); }, 2000);
});

p.catch((error) => { console.log(error); })

지금까지 설명했던 것과 같이, pending 상태에 있다가 다른 상태로 변하는 promise 객체를 만드는 것이 아니라, 처음부터 fulfilled 상태이거나 rejected 상태인 promise 객체를 만드는 방법도 존재한다.

1.1 상태가 결정된 Promise 객체 생성

1.1.1 fulfilled 상태

promise 객체의 resolve method를 사용하면, 바로 fulfilled 상태의 promise 객체를 생성할 수 있다.

const p = Promise.resolve('success');

1.1.2 rejected 상태

promise 객체의 reject method를 사용하면, 바로 rejected 상태의 promise 객체를 생성할 수 있다.

const p = Promise.reject(new Error('fail'));

이렇게 promise 객체를 직접 만드는 코드는 promisify라고 하는 작업을 할 때 주로 작성하게 된다.



2. Promisify


아래 코드의 실행 결과를 예측해보자.

function wait(text, milliseconds) {
  setTimeout(() => text, milliseconds);
}

fetch('https://jsonplaceholder.typicode.com/users')
  .then((response) => response.text())
  .then((result) => wait(`${result} by Codeit`, 2000))
  .then((result) => { console.log(result); });

코드를 실행하면, 2초 뒤에 response 내용과 by Codeit이 붙어서 출력이 되어야 할 것 같지만, 실제로는 undefined가 출력된다.

그 이유는, wait 함수는 setTimeout 함수를 실행하기만 할 뿐 아무것도 리턴하지 않기 때문이다.

(setTimeout 함수의 testwait이 함수의 리턴값이 아님을 주의해야 한다.)

이렇게, Promise Chaining 안에서 setTimeout과 같은 비동기 실행 함수를 바로 사용하면, 나중에 실행되는 부분의 리턴값(text)를 Promise Chain에서 사용할 수 없게 되는데,

이를 해결하기 위한 방법이 바로 promise 객체를 직접 생성하는 것이다.

위 코드를 아래와 같이 수정해보자.

function wait(text, milliseconds) {
  const p = new Promise((resolve, reject) => {
    setTimeout(() => { resolve(text); }, 2000);
  });
  return p;
}

fetch('https://jsonplaceholder.typicode.com/users')
  .then((response) => response.text())
  .then((result) => wait(`${result} by Codeit`, 2000))
  .then((result) => { console.log(result); });

wait 함수 내에서 p라는 promise 객체를 직접 생성하였고, executor 함수 안에서 setTimeout 함수를 호출하고 있다.

이후, setTimeout 함수 안의 콜백에서 resolve 함수를 호출할 때 파라미터로 text를 받고 있다.

이 경우에는, 앞선 경우와는 다르게, p라는 promise 객체가 2초 후에 fulfilled 상태가 될 것이고, 그 작업 성공 결과가 text라는 파라미터의 값이 되어, 결과적으로 wait 함수가 p라는 promise 객체를 리턴할 수 있게 된다.

이와 같이, 전통적인 형식의 비동기 실행 함수를 promise 객체로 감싸서 그 promise 객체를 리턴하는 형식으로 만드는 작업을 Promisify라고 한다.

단, 모든 비동기 실행 함수를 Promisify할 수 있는 것은 아니며, 기존의 비동기 실행 함수들 중, 그 콜백을 한 번만 실행하는 것들, 예를 들면, setTimeout, readFile 등과 같은 것들만 promisify를 할 수 있다.

그 이유는, promise 객체는 한 번 pending 상태에서 fulfilled 또는 rejected 상태가 되면, 그 뒤로는 그 상태와 결과가 바뀌지 않기 때문이다.

때문에 아래와 같이 코드를 작성하게 되면, 처음에 1이 출력된 이후에, 그 다음 count 값들은 출력되지 않는다.

const box = document.getElementById('test');
let count = 0;

function addEventListener_promisified(obj, eventName) { // 이런 Promisify는 하지 마세요
  const p = new Promise((resolve, reject) => {
    obj.addEventListener(eventName, () => { // addEventListener 메소드
      count += 1;
      resolve(count);
    });
  });
  return p;
}

addEventListener_promisified(box, 'click').then((eventCount) => { console.log(eventCount); });
profile
프론트엔드 개발자가 되기 위해 노력 중인 새싹🌱 입니다.

0개의 댓글

관련 채용 정보