본문 바로가기
Archive

Promise의 5가지 API

by livemehere 2022. 9. 4.

Promise.all(iterable)

완료된는 순서가 상관없는 여러개의 promise를 비동기적으로 실행하고, 결과값을 한번에 받는 함수

let urls = [
  'https://api.github.com/users/iliakan',
  'https://api.github.com/users/Violet-Bora-Lee',
  'https://api.github.com/users/jeresig'
];

// fetch를 사용해 url을 프라미스로 매핑합니다.
let requests = urls.map(url => fetch(url));

// Promise.all은 모든 작업이 이행될 때까지 기다립니다.
Promise.all(requests)
  .then(responses => responses.forEach(
    response => alert(`${response.url}: ${response.status}`)
  ));

fetch 예시

let names = ['iliakan', 'Violet-Bora-Lee', 'jeresig'];

let requests = names.map(name => fetch(`https://api.github.com/users/${name}`));

Promise.all(requests)
  .then(responses => {
    // 모든 응답이 성공적으로 이행되었습니다.
    for(let response of responses) {
      alert(`${response.url}: ${response.status}`); // 모든 url의 응답코드가 200입니다.
    }

    return responses;
  })
  // 응답 메시지가 담긴 배열을 response.json()로 매핑해, 내용을 읽습니다.
  .then(responses => Promise.all(responses.map(r => r.json())))
  // JSON 형태의 응답 메시지는 파싱 되어 배열 'users'에 저장됩니다.
  .then(users => users.forEach(user => alert(user.name)));

 

all 은 전달된 프로미스중 하나라도 거부되면 모두 거부처리된다.

또한 Promise.all(interable) 로써 이터러블객체를 받는데, 프로미스가 아닌 객체일때는 그대로 결과에 담긴다.

 

Promise.allSettled(iterable)

all과 동일하지만, 성공과 실패의 여부에 따라서, 결과값을 온전히 보존한다.

let urls = [
  'https://api.github.com/users/iliakan',
  'https://api.github.com/users/Violet-Bora-Lee',
  'https://no-such-url'
];

Promise.allSettled(urls.map(url => fetch(url)))
  .then(results => { // (*)
    results.forEach((result, num) => {
      if (result.status == "fulfilled") {
        alert(`${urls[num]}: ${result.value.status}`);
      }
      if (result.status == "rejected") {
        alert(`${urls[num]}: ${result.reason}`);
      }
    });
  });
[
  {status: 'fulfilled', value: ...응답...},
  {status: 'fulfilled', value: ...응답...},
  {status: 'rejected', reason: ...에러 객체...}
]

Promise.race(iterable)

all 과 동일하지만, 가장먼저 완료된 결과(혹은에러)를 반환한다

Promise.race([
  new Promise((resolve, reject) => setTimeout(() => resolve(1), 1000)),
  new Promise((resolve, reject) => setTimeout(() => reject(new Error("에러 발생!")), 2000)),
  new Promise((resolve, reject) => setTimeout(() => resolve(3), 3000))
]).then(alert); // 1

Promise.resolve(value)

결과값을 프로미스를 반환하도록 할 때 사용한다.

예를들면 캐싱을 사용할 때, 기존함수는 프로스를 반환한다고하면,

캐싱된 값을 프로미스로 변환 시켜서 반환해야 일관성이 유지된다.

let cache = new Map();

function loadCached(url) {
  if (cache.has(url)) {
    return Promise.resolve(cache.get(url)); // (*)
  }

  return fetch(url)
    .then(response => response.text())
    .then(text => {
      cache.set(url,text);
      return text;
    });
}

Promise.reject(error)

resolve와 동일한 메커니즘으로 에러를 프로미스로 반환할 때 사용한다.

 

callback기반의 함수를 promise화 하기

오래된 라이브러리는 promise방식으로 사용되지 않은 것들이있고,

그것을 promise로 바꾸는것은 그렇렇게어렵지 않다.

function loadScript(src, callback) {
  let script = document.createElement("script");
  script.src = src;

  script.onload = () => callback(null, script);
  script.onerror = () =>
    callback(new Error(`${src}를 불러오는 도중에 에러가 발생함`));

  document.head.append(script);
}

let loadPromise = function (src) {
  return new Promise((resolve, reject) => {
    loadScript(src, (error, script) => {
      if (err) {
        reject(err);
      } else {
        resolve(script);
      }
    });
  });
};

하지만 콜백함수를 여러번 호출하는 경우라면 변경할 수 없다. promise는 resolve, reject 중 하나가 호출되면 그대로 끝이기 때문이다.

콜백을 단 한번만 호출하는 경우에만 적용할 수 있다.

반응형

'Archive' 카테고리의 다른 글

JS 모듈  (0) 2022.09.04
제너레이터  (0) 2022.09.04
try ... catch 와 에러 핸들링  (0) 2022.09.04
내장 클래스 확장하기  (0) 2022.09.03
class의 정적 메서드, 정적 프로퍼티  (0) 2022.09.03