An Overview of JavaScript Promises - Lee-hyuna/33-js-concepts-kr GitHub Wiki

μžλ°”μŠ€ν¬λ¦½νŠΈ ν”„λΌλ―ΈμŠ€μ˜ κ°œμš”

원문 : https://www.sitepoint.com/overview-javascript-promises/

이 νŠœν† λ¦¬μ–Όμ€ μžλ°”μŠ€ν¬λ¦½νŠΈ ν”„λΌλ―ΈμŠ€μ˜ 기초λ₯Ό 닀루며, μžλ°”μŠ€ν¬λ¦½νŠΈ κ°œλ°œμ—μ„œ 이λ₯Ό ν™œμš©ν•˜λŠ” 방법을 μ•Œλ €μ€λ‹ˆλ‹€.

μ›Ήκ°œλ°œμ—μ„œ ν”„λΌλ―ΈμŠ€ κ°œλ…μ€ μƒˆλ‘œμš΄ 것이 μ•„λ‹™λ‹ˆλ‹€. Q, wen.js, RSVP.js λ“±λ“± μ—μ„œ 이미 많이 μ‚¬μš©λ˜μ–΄μ Έ μ™”μŠ΅λ‹ˆλ‹€. jQueryμ—μ„œ 쑰차도 ν”„λΌλ―ΈμŠ€μ™€ λΉ„μŠ·ν•œ Defferd 객체λ₯Ό 가지고 μžˆμŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ 이제 μžλ°”μŠ€ν¬λ¦½νŠΈμ—μ„œ ν”„λΌλ―ΈμŠ€λ₯Ό 기본적으둜 μ§€μ›ν•©λ‹ˆλ‹€.

κ°œμš”

ν”„λΌλ―ΈμŠ€ κ°μ²΄λŠ” 아직 μ‚¬μš©ν•  μˆ˜λŠ” μ—†μ§€λ§Œ λ‚˜μ€‘μ— νŠΉμ • μ‹œμ μ—μ„œ 해결될(resolved) 값을 λ‚˜νƒ€λƒ…λ‹ˆλ‹€. 보닀 동기적인 λ°©μ‹μœΌλ‘œ 비동기 μ½”λ“œλ₯Ό μž‘μ„±ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄ λ§Œμ•½ μ›Ήμ„œλΉ„μŠ€μ—μ„œ 비동기 ν˜ΈμΆœμ„ λ§Œλ“€μ–΄ λ‚΄κΈ° μœ„ν•΄ ν”„λΌλ―ΈμŠ€ APIλ₯Ό μ‚¬μš©ν•˜λŠ” 경우, λ‚˜μ€‘μ— μ›Ήμ„œλΉ„μŠ€μ—μ„œ λ°˜ν™˜ν•  데이터인 ν”„λΌλ―ΈμŠ€ 객체λ₯Ό λ§Œλ“­λ‹ˆλ‹€. 주의 사항은 μ‹€μ œ 데이터λ₯Ό 아직 μ‚¬μš©ν•  수 μ—†λ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€. μš”μ²­μ΄ μ™„λ£Œλ˜λ©΄ μ›Ήμ„œλΉ„μŠ€μ— 응닡이 λ°˜ν™˜λ©λ‹ˆλ‹€. κ·ΈλŸ¬λŠ” λ™μ•ˆ ν”„λΌλ―ΈμŠ€ κ°μ²΄λŠ” μ‹€μ œ 데이터에 λŒ€ν•œ ν”„λ‘μ‹œ 역할을 ν•©λ‹ˆλ‹€. λ˜ν•œ μ½œλ°±μ„ ν”„λΌλ―ΈμŠ€ 객체에 첨뢀할 수 있으며 μ‹€μ œ 데이터λ₯Ό μ‚¬μš©ν•  수 있게 되면 호좜이 λ©λ‹ˆλ‹€.

API

μ‹œμž‘ν•˜κΈ° μœ„ν•΄μ„œ μƒˆλ‘œμš΄ ν”„λΌλ―ΈμŠ€ 객체λ₯Ό μƒμ„±ν•˜λŠ” λ‹€μŒ μ½”λ“œλ₯Ό μ‚΄νŽ΄λ³΄κ² μŠ΅λ‹ˆλ‹€.:

const promise = new Promise((resolve, reject) => {
  //asynchronous code goes here
});

μƒˆλ‘œμš΄ ν”„λΌλ―ΈμŠ€ 객체λ₯Ό μΈμŠ€ν„΄μŠ€ν™”ν•˜κ³  콜백 ν•¨μˆ˜λ₯Ό μ „λ‹¬ν•˜λŠ” κ²ƒμœΌλ‘œ μ‹œμž‘ν•©λ‹ˆλ‹€. 콜백 ν•¨μˆ˜λŠ” resolve와 reject ν•¨μˆ˜λ₯Ό 두 인자둜 전달 ν•©λ‹ˆλ‹€.

비동기 μ½”λ“œλŠ” ν•΄λ‹Ή μ½œλ°±μ— λ“€μ–΄κ°‘λ‹ˆλ‹€. λ§Œμ•½ μ„±κ³΅ν•œλ‹€λ©΄ ν”„λΌλ―ΈμŠ€λŠ” resolve()ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜κ³ , 였λ₯˜κ°€ λ°œμƒν•˜λ©΄ reject() ν•¨μˆ˜κ°€ Error객체와 ν•¨κ»˜ 호좜이 λ©λ‹ˆλ‹€.

이것은 ν”„λΌλ―ΈμŠ€κ°€ κ±°λΆ€ λ˜μ—ˆμŒμ„ λ‚˜νƒ€λƒ…λ‹ˆλ‹€.

ν”„λΌλ―ΈμŠ€λ₯Ό μ‚¬μš©ν•œ κ°„λ‹¨ν•œ 것을 λ§Œλ“€μ–΄ λ΄…μ‹œλ‹€. JSON 포맷으둜 λ°˜ν™˜λ˜λŠ” random jokeλ₯Ό μ‚¬μš©ν•œ μ›Ήμ„œλΉ„μŠ€μ— 비동기 μš”μ²­μ„ ν•©λ‹ˆλ‹€. μ•„λž˜μ˜ μ½”λ“œμ— ν”„λΌλ―ΈμŠ€λ₯Ό μ‚¬μš©ν•œ 예λ₯Ό λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€.:

const promise = new Promise((resolve, reject) => {
  const request = new XMLHttpRequest();

  request.open('GET', 'https://api.icndb.com/jokes/random');
  request.onload = () => {
    if (request.status === 200) {
      resolve(request.response); // we got data here, so resolve the Promise
    } else {
      reject(Error(request.statusText)); // status is not 200 OK, so reject
    }
  };

  request.onerror = () => {
    reject(Error('Error fetching data.')); // error occurred, reject the  Promise
  };

  request.send(); // send the request
});

console.log('Asynchronous request made.');

promise.then((data) => {
  console.log('Got data! Promise fulfilled.');
  document.body.textContent = JSON.parse(data).value.joke;
}, (error) => {
  console.log('Promise rejected.');
  console.log(error.message);
});

이전 μ½”λ“œμ—μ„œ ν”„λΌλ―ΈμŠ€ μƒμ„±μžλŠ” μ›Ήμ„œλΉ„μŠ€λ‘œ λΆ€ν„° 데이터λ₯Ό κ°€μ Έμ˜€λŠ”λ° μ‚¬μš©λ˜λŠ” 비동기 μ½”λ“œλ₯Ό 포함가 ν¬ν•¨λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

μ—¬κΈ°μ—μ„œ, https://api.icndb.com/jokes/random에 Ajax μš”μ²­μœΌλ‘œ μƒμ„±ν•˜μ—¬ random jokeλ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€. JSON이 μ›Ήμ„œλ²„λ‘œ λΆ€ν„° 응닡 λ°›μœΌλ©΄, 이것은 resolve() ν•¨μˆ˜λ‘œ λ³΄λ‚΄μ§‘λ‹ˆλ‹€. λ§Œμ•½ μ–΄λŠ 였λ₯˜λΌλ„ λ°œμƒν•œλ‹€λ©΄ reject()λŠ” Error 객체와 ν•¨κ»˜ 호좜이 λ©λ‹ˆλ‹€.

ν”„λΌλ―ΈμŠ€ μ˜€λΈŒμ νŠΈκ°€ μΈμŠ€ν„΄μŠ€ν™” λ˜μ—ˆμ„ λ•Œ, λ‚˜μ€‘μ— μ‚¬μš©κ°€λŠ₯ν•œ 데이터λ₯Ό ν”„λ‘μ‹œλ‘œ λΆ€ν„° λ°›μŠ΅λ‹ˆλ‹€. μ•žμœΌλ‘œ μ–΄λŠ μ‹œμ μ— μ›Ήμ„œλΉ„μŠ€μ—μ„œ 일뢀 데이터가 λ°›ν™˜ 될 것이라고 κΈ°λŒ€ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. κ·Έλž˜μ„œ μ–΄λ–»κ²Œ μ–Έμ œ μ‚¬μš© κ°€λŠ₯ν•œ 데이터인지 μ•Œ 수 μžˆμ„κΉŒμš”? μ–Έμ œ μ‚¬μš© κ°€λŠ₯ν•œ 데이터인지 μ•„λŠ” 것은 Promise.then() ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. ν•¨μˆ˜λŠ” μ„±κ³΅ν•œ 경우의 콜백 ν•¨μˆ˜μ™€ μ‹€νŒ¨ν•œ 경우의 μ½œλ°±ν•¨μˆ˜μΈ 2개의 인자λ₯Ό κ°€μ§‘λ‹ˆλ‹€. 이듀 μ½œλ°±ν•¨μˆ˜λŠ” ν”„λΌλ―ΈμŠ€κ°€ 정해지면 (즉, μ‹€ν–‰ λ˜λŠ” κ±°λΆ€) 호좜이 λ©λ‹ˆλ‹€. λ§Œμ•½ ν”„λΌλ―ΈμŠ€κ°€ 싀행이 λ˜μ–΄ 진닀면 μ„±κ³΅ν•œ μ½œλ°±μ€ resolve()에 μ „λ‹¬ν•œ μ‹€μ œ 데이터λ₯Ό 받을 수 μžˆμŠ΅λ‹ˆλ‹€. λ§Œμ•½ ν”„λΌλ―ΈμŠ€κ°€ κ±°λΆ€ λœλ‹€λ©΄ μ‹€νŒ¨ν•œ 콜백이 호좜 λ©λ‹ˆλ‹€. reject() ν•¨μˆ˜κ°€ μ „λ‹¬ν•œ 것은 μ½œλ°±μ— 인수둜 μ „λ‹¬λ©λ‹ˆλ‹€.

μ½”λ“œνŽœμ˜ μ˜ˆμ‹œ μž…λ‹ˆλ‹€. μƒˆλ‘œμš΄ random jokeλ₯Ό 보렀면 μ½”λ“œνŽœμ΄ μ‚½μž…λœ ν™”λ©΄μ—μ„œ 였λ₯Έμͺ½ ν•˜λ‹¨μ— μžˆλŠ” RETURN λ²„νŠΌμ„ λˆ„λ₯΄μ„Έμš”. λ˜ν•œ μ½”λ“œμ˜ λ‹€λ₯Έ 뢀뢄이 μ‹€ν–‰λ˜λŠ” μˆœμ„œλ₯Ό λ³Ό 수 μžˆλ„λ‘ λΈŒλΌμš°μ € μ½˜μ†”μ„ μ—΄μ–΄μ£Όμ„Έμš”.

μ½”λ“œνŽœμ½”λ“œ

const promise = new Promise((resolve, reject) => {
  const request = new XMLHttpRequest();

  request.open("GET", "https://api.icndb.com/jokes/random");
  request.onload = () => {
    if (request.status === 200) {
      resolve(request.response); 
    } else {
      reject(Error(request.statusText));
    }
  };

  request.onerror = () => {
    reject(Error("Error fetching data."));
  };

  request.send();
});

console.log("Asynchronous request made.");

promise.then(
  data => {
    console.log("Got data! Promise fulfilled.");
    document.body.textContent = JSON.parse(data).value.joke;
  },
  error => {
    console.log("Promise rejected.");
    console.log(error.message);
  }
);

ν”„λΌλ―ΈμŠ€μ—λŠ” μ„Έ 가지 μƒνƒœκ°€ μžˆμ„ 수 μžˆμŠ΅λ‹ˆλ‹€.:

  • 보λ₯˜μ€‘ (싀행도 μ•„λ‹ˆκ³  거뢀도 μ•„λ‹˜)
  • μ‹€ν–‰
  • κ±°λΆ€

μ½”λ“œμ—μ„œ μ ‘κ·Όν•  수 μ—†κ³  λΉ„κ³΅κ°œμΈ Promise.status 속성은 μ΄λ ‡λ‚˜ μƒνƒœμ— λŒ€ν•œ 정보λ₯Ό μ œκ³΅ν•©λ‹ˆλ‹€. ν”„λΌλ―ΈμŠ€κ°€ κ±°λΆ€λ˜κ±°λ‚˜ μ‹€ν–‰λ˜λ©΄ μƒνƒœλŠ” 영ꡬ적으둜 연관이 λ˜μ–΄ μ§‘λ‹ˆλ‹€. 이 μ˜λ―ΈλŠ” ν”„λΌλ―ΈμŠ€λŠ” ν•œ 번만 μ„±κ³΅ν•˜κ±°λ‚˜ μ‹€νŒ¨ν•  수 μžˆμŒμ„ μ˜λ―Έν•©λ‹ˆλ‹€. λ§Œμ•½ ν”„λΌλ―ΈμŠ€κ°€ 이미 μ‹€ν–‰λ˜μ—ˆκ³  λ‚˜μ€‘μ— 두 개의 콜백으둜 then()을 μ²¨λΆ€ν•˜λ©΄ 성곡 콜백이 μ˜¬λ°”λ₯΄κ²Œ ν˜ΈμΆœλ©λ‹ˆλ‹€. κ·Έλž˜μ„œ ν”„λΌλ―ΈμŠ€μ˜ μ„Έκ³„μ—μ„œλŠ” ν”„λΌλ―ΈμŠ€κ°€ μ–Έμ œ μ •ν•΄μ§€λŠ”μ§€μ— 관심이 μ—†μŠ΅λ‹ˆλ‹€. ν”„λΌλ―ΈμŠ€λŠ” μ΅œμ’… κ²°κ³Όμ—λ§Œ 관심이 μžˆμŠ΅λ‹ˆλ‹€.

ν”„λΌλ―ΈμŠ€ 체이닝

가끔씩은 ν”„λΌλ―ΈμŠ€λ₯Ό μ²΄μ΄λ‹ν•˜λŠ” 것이 λ°”λžŒμ§ν•©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄ μ—¬λŸ¬ 비동기 μž‘μ—…μ„ μˆ˜ν–‰ν• λ•Œ μž…λ‹ˆλ‹€. ν•œ μž‘μ—…μ—μ„œ 데이터λ₯Ό μ œκ³΅ν•˜λ©΄ ν•΄λ‹Ή 데이터 λ“±μ—μ„œ λ‹€λ₯Έ μž‘μ—…μ„ μˆ˜ν–‰ν•˜κΈ° μ‹œμž‘ν•©λ‹ˆλ‹€. ν”„λΌλ―ΈμŠ€λŠ” μ•„λž˜μ˜ μ˜ˆμ‹œ μ½”λ“œμ—μ„œ 처럼 ν•¨κ»˜ 묢을 수 μžˆμ„ 수 μžˆμŠ΅λ‹ˆλ‹€.

function getPromise(url) {
  // return a Promise here
  // send an async request to the url as a part of promise
  // after getting the result, resolve the promise with it
}

const promise = getPromise('some url here');

promise.then((result) => {
  //we have our result here
  return getPromise(result); //return a promise here again
}).then((result) => {
  //handle the final result
});

κΉŒλ‹€λ‘œμš΄ 뢀뢄은 then()μ•ˆμ— κ°„λ‹¨ν•œ 값을 λ°˜ν™˜ν•˜λ©΄ κ·Έ λ‹€μŒ λ°˜ν™˜ κ°’μœΌλ‘œ λ‹€μŒ then()이 ν˜ΈμΆœλœλ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ λ§Œμ•½ then()μ•ˆμ— ν”„λΌλ―ΈμŠ€λ₯Ό λ°˜ν™˜ν•˜λ©΄ λ‹€μŒ then()κ°€ κ·Έ ν”„λΌλ―ΈμŠ€λ₯Ό κΈ°λ‹€λ Έλ‹€κ°€ κ·Έ ν”„λΌλ―ΈμŠ€κ°€ 정해지면 호좜이 λ©λ‹ˆλ‹€.

μ—λŸ¬ 핸듀링

then()ν•¨μˆ˜λŠ” 두 개의 μ½œλ°±μ„ 인자둜 λ°›λŠ”λ‹€λŠ” 것을 μ•Œκ³  μžˆμŠ΅λ‹ˆλ‹€. ν”„λΌλ―ΈμŠ€κ°€ κ±°λΆ€λ˜λ©΄ λ‘λ²ˆμ§Έ ν”„λΌλ―ΈμŠ€κ°€ 호좜이 될 κ²ƒμž…λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ ν”„λΌλ―ΈμŠ€λ₯Ό κ±°λΆ€λ₯Ό μ²˜λ¦¬ν•˜λŠ” 데 μ‚¬μš©ν•  수 μžˆλŠ” catch()ν•¨μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. λ‹€μŒ μ½”λ“œλ₯Ό μ‚΄νŽ΄λ³΄μ‹­μ‹œμ˜€.

promise.then((result) => {
  console.log('Got data!', result);
}).catch((error) => {
  console.log('Error occurred!', error);
});

μœ„μ˜ μ½”λ“œλŠ” μ•„λž˜μ˜ μ½”λ“œμ™€ κ°™μŠ΅λ‹ˆλ‹€.

promise.then((result) => {
  console.log('Got data!', result);
}).then(undefined, (error) => {A
  console.log('Error occurred!', erroAr);
});

ν”„λΌλ―ΈμŠ€κ°€ κ±°λΆ€λ˜μ—ˆκ³  then()에 μ‹€νŒ¨ 콜백이 μ—†μœΌλ©΄, μ œμ–΄λŠ” μ‹€νŒ¨ 콜백 λ˜λŠ” λ‹€μŒ catch() κ·Έλ‹€μŒ then으둜 진행이 λ©λ‹ˆλ‹€. λͺ…μ‹œμ μ€ ν”„λΌλ―ΈμŠ€ 거뢀와 달리 catch()λŠ” ν”„λΌλ―ΈμŠ€ μƒμ„±μž μ½œλ°±μ—μ„œ μ˜ˆμ™Έκ°€ λ°œμƒν•˜λ©΄ ν˜ΈμΆœλ©λ‹ˆλ‹€. κ·Έλž˜μ„œ 둜그 기둝을 μœ„ν•΄ catch()λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€. try...catchλ₯Ό μ‚¬μš©ν•˜μ—¬ 였λ₯˜λ₯Ό μ²˜λ¦¬ν•  수 μžˆμ§€λ§Œ 비동기 λ˜λŠ” 동기 였λ₯˜λŠ” 'catch()'에 μ˜ν•΄ μž‘νžˆλ―€λ‘œ ν”„λΌλ―ΈμŠ€μ—λŠ” ν•„μš”ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

κ²°λ‘ 

μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ μƒˆλ‘œμš΄ ν”„λΌλ―ΈμŠ€ APIλ₯Ό μ†Œκ°œν•˜μ˜€μŠ΅λ‹ˆλ‹€. λΆ„λͺ…νžˆ 비동기 μ½”λ“œλ₯Ό 맀우 μ‰½κ²Œ μž‘μ„±ν•  수 μžˆμŠ΅λ‹ˆλ‹€. λ‚˜μ€‘μ— 비동기 μ½”λ“œμ—μ„œ μ–΄λ–€ 값이 λ°˜ν™˜λ  지 λͺ¨λ₯Έ 채 ν‰μ†ŒλŒ€λ‘œ 진행할 μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. μ—¬κΈ°μ—μ„œ 닀루지 μ•Šμ€ APIκ°€ 더 μžˆμŠ΅λ‹ˆλ‹€. ν”„λΌλ―ΈμŠ€μ— μ’€ 더 λ§Žμ€ λ‚΄μš©μ„ 배우기 μ›ν•œλ‹€λ©΄ A Deeper Dive Into JavaScript Promises 글을 μ’€ 더 ν™•μΈν•˜μ„Έμš”.