How to implement a promise-based API

김동현·2023년 3월 10일
0

자바스크립트

목록 보기
14/22

Promise 기반의 API를 사용해서 Promise 객체를 얻는 경우가 대부분이지만, Promise 객체를 반환하는 API를 직접 구현해야 할 때도 있다.

그에 대해 알아보자.

Implementing an alarm() API

이 예제에서는 alarm() 이라는 Promise 기반의 API를 구현한다.

깨울 사람의 이름과 지금으로 부터 몇초 후인지를 결정하는 시간이 매개변수로 사용된다.

시간이 다 지나면 깨울 사람의 이름을 포함하여 "Wake up!" 메시지를 보낼 것이다.

Wrapping setTimeout()

alarm() 함수를 만들기 위해 setTimeout() API를 사용할 것이다.

setTimeout() API는 콜백 함수와 delay(밀리초 단위)를 전달 받는다.

setTimeout() 이 호출될 때, 전달 받은 delay로 설정된 타이머가 흐르기 시작하고 시간이 만료되면 전달 받은 콜백 함수를 호출한다.

<button id="set-alarm">Set alarm</button>
<div id="output"></div>
const output = document.querySelector('#output');
const button = document.querySelector('#set-alarm');

function setAlarm() {
  setTimeout(() => {
    output.textContent = 'Wake up!';
  }, 1000);
}

button.addEventListener('click', setAlarm);

The Promise() constructor

alarm() 함수는 타이머가 만료되면 fulfilled Promise를 반환한다.

그리고 "Wake up!" 메시지를 then() 핸들러로 전달한다.

alarm() 의 delay 매개변수에 음수가 전달되면 rejected Promise를 반환한다.

여기서 핵심은 Promise() constructor이다.

Promise() constructor는 매개변수로 하나의 함수를 전달받는다.

전달 받는 이 함수를 Executor(실행자)라고 부른다.

즉, 새 Promise를 만들려면 executor을 구현해서 constructor를 호출해야 한다.

Executor는 두 개의 매개변수를 사용하는데 일반적으로 resolvereject 라고 부른다.

Executor 내부에서 비동기 함수를 호출한다.

비동기 함수가 성공하면 resolve() 를 호출하고 실패하면 reject() 를 호출한다.

executor에서 오류가 발생하면 자동으로 reject() 가 호출되므로 명시적으로 호출하지 않아도 된다.

resolve()reject() 는 하나의 argument를 가지는데 모든 유형의 값을 전달받을 수 있다.

function alarm(person, delay) {
  return new Promise((resolve, reject) => {
    if (delay < 0) {
      throw new Error('Alarm delay must not be negative');
    }
    setTimeout(() => {
      resolve(`Wake up, ${person}!`);
    }, delay);
  });
}
  • delay 가 음수인지 아닌지 확인하고 음수인 경우 오류를 발생시킨다.
    오류가 발생되면 자동으로 Error객체를 전달받은 reject() 가 호출된다.

  • setTimeout() 함수에 콜백함수와 delay를 전달하여 호출한다.
    콜백 함수는 타이머가 만료되면 호출되고, 콜백 함수내부에서 "Wake up!" 메시지를 resolve() 함수에 전달하여 호출한다.

Using the alarm() API

완성된 코드는 다음과 같다.

const name = document.querySelector('#name');
const delay = document.querySelector('#delay');
const button = document.querySelector('#set-alarm');
const output = document.querySelector('#output');

function alarm(person, delay) {
  return new Promise((resolve, reject) => {
    if (delay < 0) {
      throw new Error('Alarm delay must not be negative');
    }
    setTimeout(() => {
      resolve(`Wake up, ${person}!`);
    }, delay);
  });
}

button.addEventListener('click', () => {
  alarm(name.value, delay.value)
    .then((message) => output.textContent = message)
    .catch((error) => output.textContent = `Couldn't set alarm: ${error}`);
});

실행 화면

Using async and await with the alarm() API

alarm() 함수가 Promise를 반환하기 때문에 Promise chaining, Promise.all() , async / await 와 같은 Promise 기반 코드를 사용할 수 있다.

const name = document.querySelector('#name');
const delay = document.querySelector('#delay');
const button = document.querySelector('#set-alarm');
const output = document.querySelector('#output');

function alarm(person, delay) {
  return new Promise((resolve, reject) => {
    if (delay < 0) {
      throw new Error('Alarm delay must not be negative');
    }
    setTimeout(() => {
      resolve(`Wake up, ${person}!`);
    }, delay);
  });
}

button.addEventListener('click', async () => {
  try {
    const message = await alarm(name.value, delay.value);
    output.textContent = message;
  }
  catch (error) {
    output.textContent = `Couldn't set alarm: ${error}`;
  }
});

[참고] : MDN

profile
프론트에_가까운_풀스택_개발자

0개의 댓글