Language/JavaScript

πŸ“š μžλ°”μŠ€ν¬λ¦½νŠΈ Promise κ°œλ… & 문법 μ •λ³΅ν•˜κΈ°

인파_ 2021. 9. 26. 15:44

js-promise

콜백 지μ˜₯을 νƒˆμΆœν•˜λŠ” μƒˆλ‘œμš΄ 문법

μžλ°”μŠ€ν¬λ¦½νŠΈμ—μ„œ '비동기 처리' λž€ ν˜„μž¬ 싀행쀑인 μž‘μ—…κ³ΌλŠ” λ³„λ„λ‘œ λ‹€λ₯Έ μž‘μ—…μ„ μˆ˜ν–‰ν•˜λŠ” 것을 λ§ν•œλ‹€. 예λ₯Ό λ“€μ–΄ μ„œλ²„μ—μ„œ 데이터λ₯Ό λ°›μ•„μ˜€λŠ” μž‘μ—…μ€ μ‹œκ°„μ΄ 걸리기 λ•Œλ¬Έμ— μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ μ„œλ²„ 호좜 ν•¨μˆ˜λŠ” 비동기 ν•¨μˆ˜(--링크--)둜 이루어져 μžˆλ‹€.

λΉ„λ™κΈ°λŠ” νŠΉμ • μ½”λ“œμ˜ 싀행이 μ™„λ£Œλ  λ•ŒκΉŒμ§€ 기닀리지 μ•Šκ³  λ‹€μŒ μ½”λ“œλ₯Ό λ¨Όμ € μˆ˜ν–‰ν•˜λŠ” 방식이기 λ•Œλ¬Έμ—, 만일 비동기 μž‘μ—…μ˜ 결과에 따라 λ‹€λ₯Έ μž‘μ—…μ„ μˆ˜ν–‰ν•΄μ•Ό ν•  λ•ŒλŠ” μ „ν†΅μ μœΌλ‘œ 콜백 ν•¨μˆ˜λ₯Ό μ‚¬μš©ν–ˆλ‹€. 콜백 ν•¨μˆ˜λž€ 비동기 μž‘μ—…μ΄ μ™„λ£Œλ˜λ©΄ ν˜ΈμΆœλ˜λŠ” ν•¨μˆ˜μ˜ μ˜λ―Έλ‘œμ„œ, 비동기 ν•¨μˆ˜μ˜ λ§€κ°œλ³€μˆ˜λ‘œ ν•¨μˆ˜ 객체λ₯Ό λ„˜κΈ°λŠ” 기법을 λ§ν•œλ‹€. κ·Έλž˜μ„œ ν•¨μˆ˜ λ‚΄λΆ€μ—μ„œ ν•¨μˆ˜ ν˜ΈμΆœμ„ 톡해 비동기 μž‘μ—…μ˜ κ²°κ³Όλ₯Ό λ°›μ•„μ„œ 인자둜 μ£Όλ©΄ 이λ₯Ό 톡해 후속 처리 μž‘μ—…μ„ μˆ˜ν–‰ν•  수 μžˆλ‹€. ν•˜μ§€λ§Œ 콜백 ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜λ©΄ μ½”λ“œκ°€ λ³΅μž‘ν•˜κ³  가독성이 λ–¨μ–΄μ§€λŠ” λ¬Έμ œκ°€ μžˆλ‹€. 특히, μ—¬λŸ¬ 개의 비동기 μž‘μ—…μ„ 순차적으둜 μˆ˜ν–‰ν•΄μ•Ό ν•  λ•ŒλŠ” 콜백 ν•¨μˆ˜κ°€ μ€‘μ²©λ˜μ–΄ μ½”λ“œμ˜ κΉŠμ΄κ°€ κΉŠμ–΄μ§€λŠ” ν˜„μƒμ΄ λ°œμƒν•œλ‹€. μ΄λŸ¬ν•œ ν˜„μƒμ„ 콜백 지μ˜₯(callback hell) 이라고 λΆ€λ₯Έλ‹€.

 

콜백 ν•¨μˆ˜μ˜ 비동기 처리 문법

숫자 n 을 νŒŒλΌλ―Έν„°λ‘œ λ°›μ•„μ™€μ„œ λ‹€μ„―λ²ˆμ— 걸쳐 1μ΄ˆλ§ˆλ‹€ 1μ”© λ”ν•΄μ„œ 좜λ ₯ν•˜λŠ” μž‘μ—…μ„ setTimeout 비동기 ν•¨μˆ˜λ‘œ κ΅¬ν˜„ν•œ μ½”λ“œμ΄λ‹€. ν•œλˆˆμ— 봐도 μ½œλ°±ν•¨μˆ˜λ₯Ό 연달아 μ¨μ„œ μ½”λ“œμ˜ κΉŠμ΄κ°€ κΉŠμ–΄μ‘Œλ‹€. 보기에 맀우 μ•ˆμ’‹μ€ κ±Έ λ³Ό 수 μžˆλ‹€.

function increaseAndPrint(n, callback) {
  setTimeout(() => {
    const increased = n + 1;
    console.log(increased);
    if (callback) {
      callback(increased); // μ½œλ°±ν•¨μˆ˜ 호좜
    }
  }, 1000);
}

increaseAndPrint(0, n => {
  increaseAndPrint(n, n => {
    increaseAndPrint(n, n => {
      increaseAndPrint(n, n => {
        increaseAndPrint(n, n => {
          console.log('끝!');
        });
      });
    });
  });
});

μ½”λ“œκ°€ 마치 '아됴겐'​ 을 λ§žμ€ κ²ƒμ²˜λŸΌ λ“€μ—¬μ“°κΈ° μ½”λ“œμ˜ κΉŠμ΄κ°€ ν™œ 처럼 νœ˜μ–΄μ Έ μžˆλŠ” μ›ƒκΈ°λŠ” λͺ¨μŠ΅μ΄λ‹€.

js-promise

μ΄λŸ¬ν•œ 콜백 ν•¨μˆ˜μ˜ μ½”λ“œ ν˜•νƒœλŠ” 콜백 ν•¨μˆ˜κ°€ μ€‘μ²©λ˜λ©΄μ„œ λ“€μ—¬μ“°κΈ° μˆ˜μ€€μ΄ κΉŠμ–΄μ Έ μ½”λ“œμ˜ 가독성을 λ–¨μ–΄λœ¨λ¦¬λ©° μ½”λ“œμ˜ 흐름을 νŒŒμ•…ν•˜κΈ° μ–΄λ €μ›Œμ§„λ‹€. λ˜ν•œ 콜백 ν•¨μˆ˜λ§ˆλ‹€ μ—λŸ¬ 처리λ₯Ό λ”°λ‘œ ν•΄μ€˜μ•Ό ν•˜κ³ , μ—λŸ¬κ°€ λ°œμƒν•œ μœ„μΉ˜λ₯Ό μΆ”μ ν•˜κΈ° νž˜λ“€κ²Œ λœλ‹€.

 

ν”„λ‘œλ―ΈμŠ€λ‘œ κ°œμ„ λœ 비동기 처리 문법

이λ₯Ό μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ Promise 객체λ₯Ό μ΄μš©ν•΄ λ¦¬νŒ©ν† λ§ν•˜λ©΄, 비동기 μž‘μ—…μ˜ κ°œμˆ˜κ°€ λ§Žμ•„μ Έλ„ λ“€μ—¬μ“°κΈ° μ½”λ“œμ˜ κΉŠμ΄κ°€ κΉŠμ–΄μ§€μ§€ μ•Šκ²Œ λœλ‹€. 아직 ν”„λ‘œλ―ΈμŠ€ 문법에 λŒ€ν•΄ 잘 λͺ¨λ₯΄μ§€λ§Œ .then() μ„ 톡해 이듀을 μ—΄κ±°ν•˜μ—¬ 비동기 처리 κ²°κ³Όλ₯Ό κΉ”λ”ν•˜κ²Œ ν‘œν˜„ν–ˆμŒμ„ λ³Ό 수 μžˆλ‹€. 

function increaseAndPrint(n) {
  return new Promise((resolve, reject)=>{
    setTimeout(() => {
      const increased = n + 1;
      console.log(increased);
      resolve(increased);
    }, 1000)
  })
}

increaseAndPrint(0)
  .then((n) => increaseAndPrint(n))
  .then((n) => increaseAndPrint(n))
  .then((n) => increaseAndPrint(n))
  .then((n) => increaseAndPrint(n)); // 체이닝 기법

이처럼 μžλ°”μŠ€ν¬λ¦½νŠΈ ν”„λ‘œλ―ΈμŠ€λŠ” 비동기 ν”„λ‘œκ·Έλž˜λ°μ˜ 근간이 λ˜λŠ” 기법 쀑 ν•˜λ‚˜μ΄λ‹€. ν”„λ‘œλ―ΈμŠ€λ₯Ό μ‚¬μš©ν•˜λ©΄ 콜백 ν•¨μˆ˜λ₯Ό λŒ€μ²΄ν•˜κ³ , 비동기 μž‘μ—…μ˜ 흐름을 μ‰½κ²Œ μ œμ–΄ν•  수 μžˆλ‹€. μ§€κΈˆλΆ€ν„° 이 μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ Promise μ‚¬μš©λ²•μ— λŒ€ν•΄ μ•Œμ•„λ³΄λ„λ‘ ν•˜μž.


μžλ°”μŠ€ν¬λ¦½νŠΈ ν”„λ‘œλ―ΈμŠ€ 객체

μžλ°”μŠ€ν¬λ¦½νŠΈ Promise κ°μ²΄λŠ” 비동기 μž‘μ—…μ˜ μ΅œμ’… μ™„λ£Œ λ˜λŠ” μ‹€νŒ¨λ₯Ό λ‚˜νƒ€λ‚΄λŠ” Arrayλ‚˜ Object 처럼 λ…μžμ μΈ 객체라고 보면 λœλ‹€. 비동기 μž‘μ—…μ΄ 끝날 λ•ŒκΉŒμ§€ κ²°κ³Όλ₯Ό κΈ°λ‹€λ¦¬λŠ” 것이 μ•„λ‹ˆλΌ, κ²°κ³Όλ₯Ό μ œκ³΅ν•˜κ² λ‹€λŠ” '약속'을 λ°˜ν™˜ν•œλ‹€λŠ” μ˜λ―Έμ—μ„œ Promise라 λͺ…λͺ… μ§€μ–΄μ‘Œλ‹€κ³  ν•œλ‹€. 

 

ν”„λ‘œλ―ΈμŠ€ 객체 κΈ°λ³Έ μ‚¬μš©λ²•

 

ν”„λ‘œλ―ΈμŠ€ 객체 생성

Promise 객체λ₯Ό μƒμ„±ν•˜λ €λ©΄ new ν‚€μ›Œλ“œμ™€ Promise μƒμ„±μž ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜λ©΄ λœλ‹€. μ΄λ•Œ Promise μƒμ„±μž μ•ˆμ— λ‘κ°œμ˜ λ§€κ°œλ³€μˆ˜λ₯Ό 가진 콜백 ν•¨μˆ˜λ₯Ό λ„£κ²Œ λ˜λŠ”λ°, 첫 번째 μΈμˆ˜λŠ” μž‘μ—…μ΄ μ„±κ³΅ν–ˆμ„ λ•Œ 성곡(resolve)μž„μ„ μ•Œλ €μ£ΌλŠ” 객체이며, 두 번째 μΈμˆ˜λŠ” μž‘μ—…μ΄ μ‹€νŒ¨ν–ˆμ„ λ•Œ μ‹€νŒ¨(reject)μž„μ„ μ•Œλ €μ£ΌλŠ” 였λ₯˜ 객체이닀.

Promise μƒμ„±μžμ•ˆμ— λ“€μ–΄κ°€λŠ” 콜백 ν•¨μˆ˜λ₯Ό executor 라고 λΆ€λ₯Έλ‹€.
const myPromise = new Promise((resolve, reject) => {
	// 비동기 μž‘μ—… μˆ˜ν–‰
    const data = fetch('μ„œλ²„λ‘œλΆ€ν„° μš”μ²­ν•  URL');
    
    if(data)
    	resolve(data); // 만일 μš”μ²­μ΄ μ„±κ³΅ν•˜μ—¬ 데이터가 μžˆλ‹€λ©΄
    else
    	reject("Error"); // 만일 μš”μ²­μ΄ μ‹€νŒ¨ν•˜μ—¬ 데이터가 μ—†λ‹€λ©΄
})

μœ„ μ½”λ“œμ—μ„œ μ„œλ²„λ‘œλΆ€ν„° μš”μ²­ν•˜λŠ” 비동기 μž‘μ—…μ΄ μ„±κ³΅ν•˜λŠλƒ μ‹€νŒ¨ν•˜λŠλƒμ— 따라 λ§€κ°œλ³€μˆ˜λ₯Ό ν˜ΈμΆœν•˜λŠ” 것이 λ‚˜λ‰¨μ„ λ³Ό 수 μžˆλ‹€. 만일 μž‘μ—…μ΄ μ„±κ³΅ν•œλ‹€λ©΄ 비동기 둜직 싀행이 μ°Έμ΄λΌλŠ” κ±Έ μ•Œλ €μ£ΌκΈ° μœ„ν•΄ 말 κ·ΈλŒ€λ‘œ resolve() 성곡 λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•œλ‹€. μ‹€νŒ¨ν•˜λ©΄ reject() λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•œλ‹€. 마치 μŠ€μœ„μΉ˜λ₯Ό λ‚΄λ € μ „κΈ°λ₯Ό 흐λ₯΄κ²Œ ν•˜κ±°λ‚˜ μ˜¬λ €μ„œ μ•ˆνλ₯΄κ²Œ ν•˜κ±°λ‚˜ 같은 원리이닀.

 

ν”„λ‘œλ―ΈμŠ€ 객체 처리

μ΄λ ‡κ²Œ λ§Œλ“€μ–΄μ§„ Promise κ°μ²΄λŠ” 비동기 μž‘μ—…μ΄ μ™„λ£Œλœ 이후에 λ‹€μŒ μž‘μ—…μ„ μ—°κ²°μ‹œμΌœ 진행할 수 μžˆλ‹€. μž‘μ—… κ²°κ³Ό 따라 .then() κ³Ό .catch() λ©”μ„œλ“œ 체이닝을 톡해 성곡과 μ‹€νŒ¨μ— λŒ€ν•œ 후속 처리λ₯Ό 진행할 수 μžˆλ‹€.

만일 μ²˜λ¦¬κ°€ μ„±κ³΅ν•˜μ—¬ ν”„λ‘œλ―ΈμŠ€ 객체 λ‚΄λΆ€μ—μ„œ resolve(data) λ₯Ό ν˜ΈμΆœν•˜κ²Œ 되면, λ°”λ‘œ .then() μœΌλ‘œ 이어져 then λ©”μ„œλ“œμ˜ 콜백 ν•¨μˆ˜μ—μ„œ 성곡에 λŒ€ν•œ μΆ”κ°€ 처리λ₯Ό μ§„ν–‰ν•œλ‹€. μ΄λ•Œ ν˜ΈμΆœν•œ resolve() ν•¨μˆ˜μ˜ λ§€κ°œλ³€μˆ˜μ˜ 값이 then λ©”μ„œλ“œμ˜ 콜백 ν•¨μˆ˜ 인자둜 λ“€μ–΄κ°€ then λ©”μ„œλ“œ λ‚΄λΆ€μ—μ„œ ν”„λ‘œλ―ΈμŠ€ 객체 λ‚΄λΆ€μ—μ„œ 닀룬 값을 μ‚¬μš©ν•  수 있게 λœλ‹€.

λ°˜λŒ€λ‘œ μ²˜λ¦¬κ°€ μ‹€νŒ¨ν•˜μ—¬ ν”„λ‘œλ―ΈμŠ€ 객체 λ‚΄λΆ€μ—μ„œ reject("Error") λ₯Ό ν˜ΈμΆœν•˜κ²Œ 되면, λ°”λ‘œ .catch() λ‘œ 이어져 catch λ©”μ„œλ“œμ˜ 콜백 ν•¨μˆ˜μ—μ„œ 성곡에 λŒ€ν•œ μΆ”κ°€ 처리λ₯Ό μ§„ν–‰ν•œλ‹€. 

myPromise
    .then((value) => { // μ„±κ³΅μ μœΌλ‘œ μˆ˜ν–‰ν–ˆμ„ λ•Œ 싀행될 μ½”λ“œ
    	console.log("Data: ", value); // μœ„μ—μ„œ return resolve(data)의 data값이 좜λ ₯λœλ‹€
    })
    .catch((error) => { // μ‹€νŒ¨ν–ˆμ„ λ•Œ 싀행될 μ½”λ“œ
     	console.error(error); // μœ„μ—μ„œ return reject("Error")의 "Error"κ°€ 좜λ ₯λœλ‹€
    })
    .finally(() => { // μ„±κ³΅ν•˜λ“  μ‹€νŒ¨ν•˜λ“  무쑰건 싀행될 μ½”λ“œ
    	
    })

 

ν”„λ‘œλ―ΈμŠ€ ν•¨μˆ˜ 등둝

μœ„μ™€ 같이 ν”„λ‘œλ―ΈμŠ€ 객체λ₯Ό λ³€μˆ˜μ— λ°”λ‘œ ν• λ‹Ήν•˜λŠ” 방식을 μ‚¬μš©ν•  μˆ˜λ„ μžˆμ§€λ§Œ, 보톡은 λ‹€μŒκ³Ό 같이 λ³„λ„λ‘œ ν•¨μˆ˜λ‘œ κ°μ‹Έμ„œ μ‚¬μš©ν•˜λŠ” 것이 μΌλ°˜μ μ΄λ‹€.

// ν”„λ‘œλ―ΈμŠ€ 객체λ₯Ό λ°˜ν™˜ν•˜λŠ” ν•¨μˆ˜ 생성
function myPromise() {
  return new Promise((resolve, reject) => {
    if (/* 성곡 쑰건 */) {
      resolve(/* κ²°κ³Ό κ°’ */);
    } else {
      reject(/* μ—λŸ¬ κ°’ */);
    }
  });
}

// ν”„λ‘œλ―ΈμŠ€ 객체λ₯Ό λ°˜ν™˜ν•˜λŠ” ν•¨μˆ˜ μ‚¬μš©
myPromise()
    .then((result) => {
      // 성곡 μ‹œ μ‹€ν–‰ν•  콜백 ν•¨μˆ˜
    })
    .catch((error) => {
      // μ‹€νŒ¨ μ‹œ μ‹€ν–‰ν•  콜백 ν•¨μˆ˜
    });

ν•¨μˆ˜λ₯Ό λ§Œλ“€κ³  κ·Έ ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜λ©΄ ν”„λ‘œλ―ΈμŠ€ μƒμ„±μžλ₯Ό return ν•¨μœΌλ‘œμ„œ, κ³§λ°”λ‘œ μƒμ„±λœ ν”„λ‘œλ―ΈμŠ€ 객체λ₯Ό ν•¨μˆ˜ λ°˜ν™˜κ°’μœΌλ‘œ μ–»μ–΄ μ‚¬μš©ν•˜λŠ” 기법이닀. μ΄λ ‡κ²Œ ν”„λ‘œλ―ΈμŠ€ 객체λ₯Ό ν•¨μˆ˜λ‘œ λ§Œλ“œλŠ” μ΄μœ λŠ” λ‹€μŒ 3가지 정도가 μžˆλ‹€.

  • μž¬μ‚¬μš©μ„± : ν”„λ‘œλ―ΈμŠ€ 객체λ₯Ό ν•¨μˆ˜λ‘œ λ§Œλ“€λ©΄ ν•„μš”ν•  λ•Œλ§ˆλ‹€ ν˜ΈμΆœν•˜μ—¬ μ‚¬μš©ν•¨μœΌλ‘œμ¨, λ°˜λ³΅λ˜λŠ” 비동기 μž‘μ—…μ„ 효율적으둜 μ²˜λ¦¬ν•  수 μžˆλ‹€.
  • 가독성 : ν”„λ‘œλ―ΈμŠ€ 객체λ₯Ό ν•¨μˆ˜λ‘œ λ§Œλ“€λ©΄ μ½”λ“œμ˜ ꡬ쑰가 λͺ…ν™•μ Έ, 비동기 μž‘μ—…μ˜ μ •μ˜μ™€ μ‚¬μš©μ„ λΆ„λ¦¬ν•˜μ—¬ μ½”λ“œμ˜ 가독성을 높일 수 μžˆλ‹€.
  • ν™•μž₯μ„± : ν”„λ‘œλ―ΈμŠ€ 객체λ₯Ό ν•¨μˆ˜λ‘œ λ§Œλ“€λ©΄ 인자λ₯Ό μ „λ‹¬ν•˜μ—¬ λ™μ μœΌλ‘œ 비동기 μž‘μ—…μ„ μˆ˜ν–‰ν•  수 μžˆλ‹€. λ˜ν•œ μ—¬λŸ¬ 개의 ν”„λ‘œλ―ΈμŠ€ 객체λ₯Ό λ°˜ν™˜ν•˜λŠ” ν•¨μˆ˜λ“€μ„ μ—°κ²°ν•˜μ—¬ λ³΅μž‘ν•œ 비동기 λ‘œμ§μ„ κ΅¬ν˜„ν•  수 μžˆλ‹€.
ν”„λ‘œλ―ΈμŠ€λ₯Ό μƒμ„±ν•˜μ—¬ λ°˜ν™˜ν•˜λŠ” ν•¨μˆ˜λ₯Ό 'ν”„λ‘œλ―ΈμŠ€ νŒ©ν† λ¦¬ ν•¨μˆ˜' 라고 λΆˆλ¦¬μš°κΈ°λ„ ν•œλ‹€.

μ΄λŸ¬ν•œ 점 λ•Œλ¬Έμ— μ‹€λ¬΄μ—μ„œ ν”„λ‘œλ―ΈμŠ€ 객체λ₯Ό μ‚¬μš©ν•  일이 μžˆλ‹€λ©΄ ν•¨μˆ˜λ‘œ 감싸 μ‚¬μš©ν•œλ‹€. κ·Έλž˜μ„œ λŒ€λΆ€λΆ„μ˜ μžλ°”μŠ€ν¬λ¦½νŠΈ 비동기 λΌμ΄λΈŒλŸ¬λ¦¬λ„ ν•¨μˆ˜ ν˜•νƒœλ‘œ ν”„λ‘œλ―ΈμŠ€ 객체λ₯Ό μ œκ³΅ν•œλ‹€. λŒ€ν‘œμ μœΌλ‘œ μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ fetch() λ©”μ„œλ“œκ°€ μžˆλŠ”λ°, 이 fetch() λ©”μ„œλ“œ λ‚΄μ—μ„œ ν”„λ‘œλ―ΈμŠ€ 객체λ₯Ό μƒμ„±ν•˜μ—¬ μ„œλ²„λ‘œλΆ€ν„° 데이터λ₯Ό κ°€μ Έμ˜€λ©΄ resolve() ν•˜μ—¬ .then() 으둜 μ²˜λ¦¬ν•˜κΈ° λ•Œλ¬Έμ΄λ‹€.

// GET μš”μ²­ μ˜ˆμ‹œ
fetch('https://jsonplaceholder.typicode.com/posts/1')
  .then((response) => response.json()) // 응닡 κ°μ²΄μ—μ„œ JSON 데이터λ₯Ό μΆ”μΆœν•œλ‹€.
  .then((data) => console.log(data)); // JSON 데이터λ₯Ό μ½˜μ†”μ— 좜λ ₯ν•œλ‹€.

ν”„λ‘œλ―ΈμŠ€ 3가지 μƒνƒœ

ν”„λ‘œλ―ΈμŠ€λŠ” 비동기 μž‘μ—…μ˜ κ²°κ³Όλ₯Ό μ•½μ†ν•˜λŠ” 것이닀. new Promise() μƒμ„±μžλ‘œ ν”„λ‘œλ―ΈμŠ€ 객체λ₯Ό μƒμ„±ν•˜λ©΄, κ·Έ 비동기 μž‘μ—…μ€ 이미 진행 쀑이고 μ–Έμ  κ°€λŠ” μ„±κ³΅ν•˜κ±°λ‚˜ μ‹€νŒ¨ν•  것이닀. μ΄λŸ¬ν•œ 진행쀑, 성곡, μ‹€νŒ¨ μƒνƒœλ₯Ό λ‚˜νƒ€λ‚΄λŠ” 것이 λ°”λ‘œ ν”„λ‘œλ―ΈμŠ€μ˜ μƒνƒœ(state)라고 λΆˆλ¦¬μš΄λ‹€. μ‰½κ²Œ λ§ν•˜μžλ©΄ μΌμ’…μ˜ ν”„λ‘œλ―ΈμŠ€ 처리 과정이라고 보면 λœλ‹€.

  1. Pending(λŒ€κΈ°) : μ²˜λ¦¬κ°€ μ™„λ£Œλ˜μ§€ μ•Šμ€ μƒνƒœ (처리 진행쀑)
  2. Fulfilled(이행) : μ„±κ³΅μ μœΌλ‘œ μ²˜λ¦¬κ°€ μ™„λ£Œλœ μƒνƒœ
  3. Eejected(κ±°λΆ€) : μ²˜λ¦¬κ°€ μ‹€νŒ¨λ‘œ λλ‚œ μƒνƒœ

promise-state

 

1. Pending μƒνƒœ

λŒ€κΈ°(pending) μƒνƒœλž€, 말 κ·ΈλŒ€λ‘œ 아직 비동기 처리 둜직이 μ™„λ£Œ λ˜μ§€ μ•Šμ€ μƒνƒœμ΄λ‹€. 예λ₯Ό λ“€μ–΄ μ•„λž˜μ™€ 같이 ν”„λ‘œλ―ΈμŠ€ 객체λ₯Ό μƒμ„±ν•˜κ³ , μƒμ„±ν•œ ν”„λ‘œλ―ΈμŠ€ 객체λ₯Ό μ½˜μ†”μ„ 찍어보면 μ•„λž˜μ™€ 같이 ν”„λ‘œλ―ΈμŠ€ 객체의 μƒνƒœκ°€ "pending"으둜 좜λ ₯되게 λœλ‹€.

const promise = new Promise((resolve, reject) => {
	setTimeout(() => {
    	resolve("처리 μ™„λ£Œ")
    }, 5000)
});
console.log(promise); // Pending (λŒ€κΈ°) μƒνƒœ

Pending

 

2. Fulfilled μƒνƒœ

μœ„μ˜ ν”„λ‘œλ―ΈμŠ€ μ½”λ“œλ₯Ό μ‹€ν–‰ν•˜κ³  5초 λ™μ•ˆ 기닀리닀가 λ‹€μ‹œ μ½˜μ†”μ„ μ°μ–΄λ³΄μž. 그럼 μ•„λž˜μ™€ 같이 이행(fulfilled) μƒνƒœλ‘œ λ³€ν•˜κ²Œ λœλ‹€.

Fulfilled

즉, 5μ΄ˆκ°€ μ§€λ‚˜ resolve() μˆ˜ν–‰λ˜λ©΄μ„œ ν”„λ‘œλ―ΈμŠ€ 성곡을 μ•Œλ¦¬λŠ” 개체λ₯Ό 호좜 ν•˜μ˜€μœΌλ‹ˆ 이행 μƒνƒœλ‘œ λ³€ν•œ 것이닀. λ”°λΌμ„œ 이행(fulfilled) μƒνƒœλž€, 비동기 처리 둜직이 μ„±κ³΅μ μœΌλ‘œ μ™„λ£Œ λ¬λ‹€λŠ” 것을 ν‘œν˜„ν•˜κΈ° μœ„ν•œ μƒνƒœλΌκ³  보면 λœλ‹€.

Fulfilled

ν”„λ‘œλ―ΈμŠ€μ˜ '이행' μƒνƒœλ₯Ό λ‹€λ₯΄κ²Œ ν‘œν˜„ν•˜μžλ©΄ 'μ™„λ£Œ' 봐도 λœλ‹€.

그리고 이행 μƒνƒœλ‘œ λ³€ν•œ ν”„λ‘œλ―ΈμŠ€ κ°μ²΄λŠ” λ°”λ‘œ μ²΄μ΄λ‹λœ .then() λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜μ—¬ 처리 κ²°κ³Ό 값을 받을 수 μžˆλŠ” 것이닀.

promise
    .then((data) => {
        console.log("ν”„λ‘œλ―ΈμŠ€κ°€ 이행 μƒνƒœκ°€ λ˜λ©΄μ„œ μ²˜λ¦¬μ— λŒ€ν•œ κ²°κ³Όλ₯Ό μˆ˜ν–‰")
    })

 

3. Rejected μƒνƒœ

resolve()λ₯Ό ν˜ΈμΆœν•¨μœΌλ‘œμ„œ ν”„λ‘œλ―ΈμŠ€ 객체 μƒνƒœκ°€ 이행(fulfilled) μƒνƒœκ°€ 됬닀면, λ°˜λŒ€λ‘œ reject()λ₯Ό ν˜ΈμΆœν•˜λ©΄ ν”„λ‘œλ―ΈμŠ€ 객체가 μ‹€νŒ¨(rejected) μƒνƒœκ°€ λœλ‹€.

Rejected

const promise = new Promise((resolve, reject) => {
	setTimeout(() => {
    	reject("처리 μ‹€νŒ¨")
    }, 5000)
});

Rejected

μ—­μ‹œ μ‹€νŒ¨ μƒνƒœλ‘œ λ³€ν•œ ν”„λ‘œλ―ΈμŠ€ κ°μ²΄λŠ” λ°”λ‘œ μ²΄μ΄λ‹λœ .catch() λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜μ—¬ 처리 μ‹€νŒ¨μ— λŒ€ν•œ 행동을 μˆ˜ν–‰ν•˜κ²Œ λœλ‹€.

promise
	.catch((error) => {
    	console.log(error);
        console.log("μ‹€νŒ¨μ— λŒ€ν•œ 후속 쑰치...")
    })

ν”„λ‘œλ―ΈμŠ€ ν•Έλ“€λŸ¬

ν”„λ‘œλ―ΈμŠ€κ°€ μƒμ„±λ˜λ©΄, κ·Έ μž‘μ—…μ€ 이미 진행 쀑이고 μ–Έμ  κ°€λŠ” μ„±κ³΅ν•˜κ±°λ‚˜ μ‹€νŒ¨ν•  것이닀. κ·Έ 성곡/μ‹€νŒ¨ κ²°κ³Όλ₯Ό .then / .catch / .finally ν•Έλ“€λŸ¬λ₯Ό 톡해 λ°›μ•„ λ‹€μŒ 후속 μž‘μ—…μ„ μˆ˜ν–‰ν•  수 μžˆλ‹€. ν”„λ‘œλ―ΈμŠ€ ν•Έλ“€λŸ¬λŠ” ν”„λ‘œλ―ΈμŠ€μ˜ μƒνƒœμ— 따라 μ‹€ν–‰λ˜λŠ” 콜백 ν•¨μˆ˜λΌκ³  보면 λœλ‹€.

  • .then() : ν”„λ‘œλ―ΈμŠ€κ°€ 이행(fulfilled)λ˜μ—ˆμ„ λ•Œ μ‹€ν–‰ν•  콜백 ν•¨μˆ˜λ₯Ό λ“±λ‘ν•˜κ³ , μƒˆλ‘œμš΄ ν”„λ‘œλ―ΈμŠ€λ₯Ό λ°˜ν™˜
  • .catch() : ν”„λ‘œλ―ΈμŠ€κ°€ κ±°λΆ€(rejected)λ˜μ—ˆμ„ λ•Œ μ‹€ν–‰ν•  콜백 ν•¨μˆ˜λ₯Ό λ“±λ‘ν•˜κ³ , μƒˆλ‘œμš΄ ν”„λ‘œλ―ΈμŠ€λ₯Ό λ°˜ν™˜
  • .finally() : ν”„λ‘œλ―ΈμŠ€κ°€ μ΄ν–‰λ˜κ±°λ‚˜ 거뢀될 λ•Œ 상관없이 μ‹€ν–‰ν•  콜백 ν•¨μˆ˜λ₯Ό λ“±λ‘ν•˜κ³ , μƒˆλ‘œμš΄ ν”„λ‘œλ―ΈμŠ€λ₯Ό λ°˜ν™˜

ν”„λ‘œλ―ΈμŠ€ ν•Έλ“€λŸ¬ ꡬ성을 보건데, 마치 try - catch - finally ꡬ쑰와 ꡉμž₯히 μœ μ‚¬ν•˜λ‹€κ³  λŠλ‚„ν…λ° κ·Έ λŠλ‚Œμ΄ λ§žλ‹€.

이미 μœ„μ—μ„œ ν”„λ‘œλ―ΈμŠ€ μƒνƒœμ— 따라 μˆ˜ν–‰λ˜λŠ” ν”„λ‘œλ―ΈμŠ€ ν•Έλ“€λŸ¬ 문법에 λŒ€ν•΄ λ‹€λ€˜μœΌλ‹ˆ 기본적인 μ‚¬μš©λ²•μ€ λ‹€λ“€ μ•Œ 것이닀. λ‹€λ§Œ 이 μ„Ήμ…˜μ—μ„œ μ†Œκ°œν•˜κ³  싢은 것은 이 ν•Έλ“€λŸ¬λ“€μ„ 체이닝(chaining) ν•˜μ—¬ μ—΄κ±°ν•˜μ—¬ λ³΅μž‘ν•˜κ²Œ μ‚¬μš©ν• λ•Œ 처리 μˆœμ„œμ— λŒ€ν•œ 뢀뢄이닀.

 

ν”„λ‘œλ―ΈμŠ€ 체이닝

ν”„λ‘œλ―ΈμŠ€ μ²΄μ΄λ‹μ΄λž€, ν”„λ‘œλ―ΈμŠ€ ν•Έλ“€λŸ¬λ₯Ό 연달아 μ—°κ²°ν•˜λŠ” 것을 λ§ν•œλ‹€. μ΄λ ‡κ²Œ ν•˜λ©΄ μ—¬λŸ¬ 개의 비동기 μž‘μ—…μ„ 순차적으둜 μˆ˜ν–‰ν•  수 μžˆλ‹€λŠ” νŠΉμ§•μ΄ μžˆλ‹€.

예λ₯Όλ“€μ–΄ μ•„λž˜λŠ” doSomething ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜μ—¬ ν”„λ‘œλ―ΈμŠ€λ₯Ό μƒμ„±ν•˜κ³ , then λ©”μ„œλ“œλ₯Ό 톡해 이행 ν•Έλ“€λŸ¬λ₯Ό μ—°κ²°ν•˜λŠ” 과정을 보여쀀닀. 각 이행 ν•Έλ“€λŸ¬λŠ” 이전 ν”„λ‘œλ―ΈμŠ€μ˜ 값에 50을 λ”ν•œ 값을 λ°˜ν™˜ν•˜κ³ , λ§ˆμ§€λ§‰ 이행 ν•Έλ“€λŸ¬λŠ” μ΅œμ’… 값을 μ½˜μ†”μ— 좜λ ₯ν•˜κ²Œ λœλ‹€.

function doSomething() {
  return new Promise((resolve, reject) => {
      resolve(100)
  });
}

doSomething()
    .then((value1) => {
        const data1 = value1 + 50;
        return data1
    })
    .then((value2) => {
        const data2 = value2 + 50;
        return data2
    })
    .then((value3) => {
        const data3 = value3 + 50;
        return data3
    })
    .then((value4) => {
        console.log(value4); // 250 좜λ ₯
    })

promise-chaining

μ΄λŸ°μ‹μœΌλ‘œ 체이닝이 κ°€λŠ₯ν•œ μ΄μœ λŠ” then ν•Έλ“€λŸ¬μ—μ„œ 값을 λ¦¬ν„΄ν•˜λ©΄, κ·Έ λ°˜ν™˜κ°’μ€ μžλ™μœΌλ‘œ ν”„λ‘œλ―ΈμŠ€ 객체둜 감싸져 λ°˜ν™˜λ˜κΈ° λ•Œλ¬Έμ΄λ‹€. 그리고 λ‹€μŒ then ν•Έλ“€λŸ¬μ—μ„œ λ°˜ν™˜λœ ν”„λ‘œλ―ΈμŠ€ 객체λ₯Ό λ°›μ•„ μ²˜λ¦¬ν•˜λŠ” 것이닀. κ·Έλž˜μ„œ ν”„λ‘œλ―ΈμŠ€ μƒνƒœμ˜ 흐름도λ₯Ό ν‘œν˜„ν•˜μžλ©΄ μ•„λž˜μ™€ 같이 λœλ‹€.

js-promise-state

 

만일 μ—°κ²°λœ 이행 ν•Έλ“€λŸ¬μ—μ„œ 쀑간에 였λ₯˜κ°€ μžˆλŠ” 처리λ₯Ό ν–‰ν•œλ‹€λ©΄ μ˜ˆμ™Έμ²˜λ¦¬λ₯Ό ν•¨μœΌλ‘œμ¨ catch ν•Έλ“€λŸ¬μ— μ ν”„ν•˜λ„λ‘ μ„€μ •ν•  수 μžˆλ‹€. μ–΄λ ΅κ²Œ μƒκ°ν•˜μ§€ 말고 try - catch 와 같이 μƒκ°ν•˜λ©΄ λœλ‹€.

function doSomething(arg) {
  return new Promise((resolve, reject) => {
      resolve(arg)
  });
}

doSomething('100A')
    .then((value1) => {
        const data1 = value1 + 50; // μˆ«μžμ— 문자λ₯Ό μ—°μ‚°

        if (isNaN(data1)) 
            throw new Error('값이 λ„˜λ²„κ°€ μ•„λ‹™λ‹ˆλ‹€')
        
        return data1
    })
    .then((value2) => {
        const data2 = value2 + 50;
        return data2
    })
    .catch((err) => {
        console.error(err);
    })

promise-chaining

만일 catch ν•Έλ“€λŸ¬ λ‹€μŒμœΌλ‘œ then ν•Έλ“€λŸ¬κ°€ μ΄μ–΄μ„œ 체이닝 λ˜μ–΄ μžˆλ‹€λ©΄, μ—λŸ¬κ°€ 처리되고 κ°€κΉŒμš΄ then ν•Έλ“€λŸ¬λ‘œ μ œμ–΄ 흐름이 λ„˜μ–΄κ°€ 싀행이 μ΄μ–΄μ§€κ²Œ λœλ‹€.

new Promise((resolve, reject) => {
  throw new Error("μ—λŸ¬ λ°œμƒ!");
})
    .catch(function(error) {
      console.log("μ—λŸ¬κ°€ 잘 μ²˜λ¦¬λ˜μ—ˆμŠ΅λ‹ˆλ‹€. μ •μƒμ μœΌλ‘œ 싀행이 μ΄μ–΄μ§‘λ‹ˆλ‹€.");
    })
    .then(() => {
        console.log("λ‹€μŒ ν•Έλ“€λŸ¬κ°€ μ‹€ν–‰λ©λ‹ˆλ‹€.")
    })
    .then(() => {
        console.log("λ‹€μŒ ν•Έλ“€λŸ¬κ°€ 또 μ‹€ν–‰λ©λ‹ˆλ‹€.")
    });

promise-chaining


ν”„λ‘œλ―ΈμŠ€ 정적 λ©”μ„œλ“œ

ν”„λ‘œλ―ΈμŠ€ κ°μ²΄λŠ” μƒμ„±μž ν•¨μˆ˜ 외에도 μ—¬λŸ¬ 가지 정적 λ©”μ„œλ“œ(static method)λ₯Ό μ œκ³΅ν•œλ‹€. 정적 λ©”μ„œλ“œλŠ” 객체λ₯Ό μ΄ˆκΈ°ν™” & μƒμ„±ν•˜μ§€ μ•Šκ³ λ„ λ°”λ‘œ μ‚¬μš©ν•  수 있기 λ•Œλ¬Έμ— 비동기 처리λ₯Ό 보닀 효율적이고 κ°„νŽΈν•˜κ²Œ κ΅¬ν˜„ν•  수 μžˆλ„λ‘ 도와쀀닀.

 

Promise.resolve()

보톡 ν”„λ‘œλ―ΈμŠ€μ˜ resolve() λ©”μ„œλ“œλŠ”, ν”„λ‘œλ―ΈμŠ€λ₯Ό μƒμ„±μžλ‘œ λ§Œλ“€κ³  κ·Έμ•ˆμ˜ 콜백 ν•¨μˆ˜μ˜ λ§€κ°œλ³€μˆ˜λ₯Ό 톡해 ν˜ΈμΆœν•˜μ—¬ μ‚¬μš©ν•΄μ™”λ‹€.

// ν”„λ‘œλ―ΈμŠ€ μƒμ„±μžλ₯Ό μ‚¬μš©ν•˜μ—¬ ν”„λ‘œλ―ΈμŠ€ 객체λ₯Ό λ°˜ν™˜ν•˜λŠ” ν•¨μˆ˜
function getPromiseNumber() {
  return new Promise((resolve, reject) => {
      const num = Math.floor(Math.random() * 10); // 0 ~ 9 μ‚¬μ΄μ˜ μ •μˆ˜
      resolve(num); // ν”„λ‘œλ―ΈμŠ€ 이행
  });
}

μ΄λŸ¬ν•œ 과정을 Promise.resolve() 정적 λ©”μ„œλ“œλ‘œ ν•œλ²ˆμ— ν˜ΈμΆœν•  수 μžˆλ„λ‘ 편의 κΈ°λŠ₯을 μ œκ³΅ν•΄ μ£ΌλŠ” κ²ƒμœΌλ‘œ 보면 λœλ‹€. κ·Έλž˜μ„œ ν”„λ‘œλ―ΈμŠ€ 정적 λ©”μ„œλ“œλ₯Ό μ΄μš©ν•˜λ©΄ ν”„λ‘œλ―ΈμŠ€ 객체와 μ „ν˜€ μ—°κ΄€μ—†λŠ” ν•¨μˆ˜ λ‚΄μ—μ„œ ν•„μš”μ— 따라 ν”„λ‘œλ―ΈμŠ€ 객체λ₯Ό λ°˜ν™˜ν•˜μ—¬ ν•Έλ“€λŸ¬λ₯Ό μ΄μš©ν•  수 μžˆλ„λ‘ μ‘μš©μ΄ κ°€λŠ₯ν•˜λ‹€. 이 방법은 비동기 μž‘μ—…μ„ μˆ˜ν–‰ν•˜μ§€ μ•ŠλŠ” ν•¨μˆ˜μ—μ„œλ„ ν”„λ‘œλ―ΈμŠ€μ˜ μž₯점을 ν™œμš©ν•˜κ³  싢은 κ²½μš°μ— μœ μš©ν•˜λ‹€.

// ν”„λ‘œλ―ΈμŠ€ 객체와 μ „ν˜€ μ—°κ΄€μ—†λŠ” ν•¨μˆ˜
function getRandomNumber() {
  const num = Math.floor(Math.random() * 10); // 0 ~ 9 μ‚¬μ΄μ˜ μ •μˆ˜
  return num;
}

// Promise.resolve() λ₯Ό μ‚¬μš©ν•˜μ—¬ ν”„λ‘œλ―ΈμŠ€ 객체λ₯Ό λ°˜ν™˜ν•˜λŠ” ν•¨μˆ˜
function getPromiseNumber() {
  const num = getRandomNumber(); // 일반 κ°’
  return Promise.resolve(num); // ν”„λ‘œλ―ΈμŠ€ 객체
}

// ν•Έλ“€λŸ¬λ₯Ό μ΄μš©ν•˜μ—¬ ν”„λ‘œλ―ΈμŠ€ 객체의 값을 μ²˜λ¦¬ν•˜λŠ” ν•¨μˆ˜
getPromiseNumber()
    .then((value) => {
      console.log(`랜덀 숫자: ${value}`);
    })
    .catch((error) => {
      console.error(error);
    });

 

Promise.reject()

λ§ˆμ°¬κ°€μ§€λ‘œ 주어진 μ‚¬μœ λ‘œ κ±°λΆ€ν•˜λŠ” Promise 객체λ₯Ό λ°˜ν™˜ν•œλ‹€.

// 주어진 μ‚¬μœ λ‘œ κ±°λΆ€λ˜λŠ” ν”„λ‘œλ―ΈμŠ€ 생성
const p = Promise.reject(new Error('error'));

// κ±°λΆ€ μ‚¬μœ λ₯Ό 좜λ ₯
p.catch(error => console.error(error)); // Error: error

 

Promise.all()

λ°°μ—΄, Map, Set에 ν¬ν•¨λœ μ—¬λŸ¬κ°œμ˜ ν”„λ‘œλ―ΈμŠ€ μš”μ†Œλ“€μ„ ν•œκΊΌλ²ˆμ— 비동기 μž‘μ—…μ„ μ²˜λ¦¬ν•΄μ•Ό ν• λ•Œ ꡉμž₯히 μœ μš©ν•œ ν”„λ‘œλ―ΈμŠ€ 정적 λ©”μ†Œλ“œμ΄λ‹€. λͺ¨λ“  ν”„λ‘œλ―ΈμŠ€ 비동기 μ²˜λ¦¬κ°€ 이행(fulfilled) λ λ•ŒκΉŒμ§€ κΈ°λ‹€λ €μ„œ, λͺ¨λ“  ν”„λ‘œλ―ΈμŠ€κ°€ μ™„λ£Œλ˜λ©΄ κ·Έλ•Œ then ν•Έλ“€λŸ¬κ°€ μ‹€ν–‰ν•˜λŠ” ν˜•νƒœλ‘œ 보면 λœλ‹€. κ°€μž₯ λŒ€ν‘œμ μΈ μ‚¬μš© μ˜ˆμ‹œλ‘œ μ—¬λŸ¬ 개의 API μš”μ²­μ„ 보내고 λͺ¨λ“  응닡을 λ°›μ•„μ•Ό ν•˜λŠ” κ²½μš°μ— μ‚¬μš©ν•  수 μžˆλ‹€.

// 1. μ„œλ²„ μš”μ²­ API ν”„λ‘œλ―ΈμŠ€ 객체 생성 (fetch)
const api_1 = fetch("https://jsonplaceholder.typicode.com/users");
const api_2 = fetch("https://jsonplaceholder.typicode.com/users");
const api_3 = fetch("https://jsonplaceholder.typicode.com/users");

// 2. ν”„λ‘œλ―ΈμŠ€ 객체듀을 λ¬Άμ–΄ λ°°μ—΄λ‘œ ꡬ성
const promises = [api_1, api_2, api_3];

// 3. Promise.all() λ©”μ„œλ“œ 인자둜 ν”„λ‘œλ―ΈμŠ€ 배열을 λ„£μ–΄, λͺ¨λ“  ν”„λ‘œλ―ΈμŠ€κ°€ 이행될 λ•ŒκΉŒμ§€ 기닀리고, 결과값을 좜λ ₯
Promise.all(promises)
    .then((results) => {
      // resultsλŠ” μ΄ν–‰λœ ν”„λ‘œλ―ΈμŠ€λ“€μ˜ 값듀을 담은 λ°°μ—΄.
      // results의 μˆœμ„œλŠ” promises의 μˆœμ„œμ™€ 일치.
      console.log(results); // [users1, users2, users3]
    })
    .catch((error) => {
      // μ–΄λŠ ν•˜λ‚˜λΌλ„ ν”„λ‘œλ―ΈμŠ€κ°€ κ±°λΆ€λ˜λ©΄ 였λ₯˜λ₯Ό 좜λ ₯
      console.error(error);
    });

 

Promise.allSettled()

Promise.all() λ©”μ„œλ“œμ˜ μ—…κ·Έλ ˆμ΄λ“œ λ²„μ „μœΌλ‘œ, 주어진 λͺ¨λ“  ν”„λ‘œλ―ΈμŠ€κ°€ 처리되면 λͺ¨λ“  ν”„λ‘œλ―ΈμŠ€ 각각의 μƒνƒœμ™€ κ°’ (λ˜λŠ” κ±°λΆ€ μ‚¬μœ )을 λͺ¨μ•„놓은 배열을 λ°˜ν™˜ν•œλ‹€.

 

πŸ“š Promise.allSettled 와 Promise.all 비ꡐ 정리

Promise.all 의 문제점 Promise.all([ promise1, promise2, ... ]) 의 ν˜•νƒœλ‘œ μ‚¬μš©λ˜λ©°, λ°°μ—΄λ‘œ 받은 λͺ¨λ“  ν”„λ‘œλ―ΈμŠ€κ°€ fulfill 된 이후, λͺ¨λ“  ν”„λ‘œλ―ΈμŠ€μ˜ λ°˜ν™˜ 값을 배열에 λ„£μ–΄ λ°˜ν™˜ν•œλ‹€. 그런데 λ§Œμ•½ 배열에 μžˆλŠ”

inpa.tistory.com

// 1초 후에 1을 λ°˜ν™˜ν•˜λŠ” ν”„λ‘œλ―ΈμŠ€
const p1 = new Promise(resolve => setTimeout(() => resolve(1), 1000));

// 2초 후에 μ—λŸ¬λ₯Ό λ°œμƒμ‹œν‚€λŠ” ν”„λ‘œλ―ΈμŠ€
const p2 = new Promise((resolve, reject) => setTimeout(() => reject(new Error('error')), 2000));

// 3초 후에 3을 λ°˜ν™˜ν•˜λŠ” ν”„λ‘œλ―ΈμŠ€
const p3 = new Promise(resolve => setTimeout(() => resolve(3), 3000));

// μ„Έ 개의 ν”„λ‘œλ―ΈμŠ€μ˜ μƒνƒœμ™€ κ°’ λ˜λŠ” μ‚¬μœ λ₯Ό 좜λ ₯
Promise.allSettled([p1, p2, p3])
	.then(result => console.log(result));

Promise.allSettled

 

Promise.any()

Promise.all() λ©”μ„œλ“œμ˜ λ°˜λŒ€ λ²„μ „μœΌλ‘œ, Promise.all() μ΄ μ£Όμ–΄μ§„ λͺ¨λ“  ν”„λ‘œλ―ΈμŠ€κ°€ λͺ¨λ‘ μ™„λ£Œν•΄μ•Όλ§Œ κ²°κ³Όλ₯Ό λ„μΆœν•œλ‹€λ©΄, Promise.any() λŠ” 주어진 λͺ¨λ“  ν”„λ‘œλ―ΈμŠ€ 쀑 ν•˜λ‚˜λΌλ„ μ™„λ£Œλ˜λ©΄ λ°”λ‘œ λ°˜ν™˜ν•˜λŠ” 정적 λ©”μ„œλ“œμ΄λ‹€.

const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("promise1 failed");
  }, 3000);
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("promise2 succeeded");
  }, 2000);
});

const promise3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("promise3 failed");
  }, 1000);
});

// promise1, promise2, promise3은 각각 3초, 2초, 1초 후에 κ±°λΆ€λ˜κ±°λ‚˜ 이행
Promise.any([promise1, promise2, promise3])
  .then((value) => {
    console.log(value); // "promise2 succeeded" 
  })
  .catch((error) => {
    console.error(error);
  });

μœ„ μ½”λ“œλ₯Ό 보면 Promise.any() λ©”μ„œλ“œμ˜ 결과둜 promise2의 μ²˜λ¦¬κ°€ κ°€μž₯ λ¨Όμ € λ„μΆœλ¨μ„ λ³Ό 수 μžˆλ‹€. μ˜€λ‘œμ§€ 첫번째둜 이행(fulfilled) 된 ν”„λ‘œλ―ΈμŠ€λ§Œμ„ μ·¨κΈ‰ν•˜κΈ° λ•Œλ¬Έμ— λ‚˜λ¨Έμ§€ promise1κ³Ό promise3의 κ±°λΆ€(rejected)λŠ” λ¬΄μ‹œλ˜κ²Œ λœλ‹€.

만일 μš”μ²­λœ λͺ¨λ“  ν”„λ‘œλ―ΈμŠ€κ°€ κ±°λΆ€(rejected)되면, AggregateError 객체λ₯Ό μ‚¬μœ λ‘œ ν•˜λŠ” κ±°λΆ€ ν”„λ‘œλ―ΈμŠ€λ₯Ό λ°˜ν™˜ν•œλ‹€.

const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("promise1 failed");
  }, 3000);
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("promise2 succeeded");
  }, 2000);
});

const promise4 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("promise4 failed");
  }, 4000);
});

Promise.any([promise1, promise3, promise4])
  .then((value) => {
    console.log(value);
  })
  .catch((error) => {
    console.error(error); // AggregateError: All promises were rejected
    console.error(error.errors); // ["promise3 failed", "promise1 failed", "promise4 failed"]
  });

 

Promise.race()

Promise.race() λŠ” Promise.any() 와 같이 μ—¬λŸ¬ 개의 ν”„λ‘œλ―ΈμŠ€ 쀑 κ°€μž₯ λ¨Όμ € 처리된 ν”„λ‘œλ―ΈμŠ€μ˜ 결과값을 λ°˜ν™˜ν•˜μ§€λ§Œ, 차이점이 μ‘΄μž¬ν•œλ‹€.

Promise.any()λŠ” κ°€μž₯ λ¨Όμ € fulfilled(이행) μƒνƒœκ°€ 된 ν”„λ‘œλ―ΈμŠ€λ§Œμ„ λ°˜ν™˜ν•˜κ±°λ‚˜, ν˜Ήμ€ μ „λΆ€ rejected(μ‹€νŒ¨) μƒνƒœκ°€λœ ν”„λ‘œλ―ΈμŠ€(AggregateError)λ₯Ό λ°˜ν™˜ν•œλ‹€. 반면 Promise.race() λŠ” fulfilled(이행), rejected(μ‹€νŒ¨) μ—¬λΆ€ 상관없이 무쑰건 μ²˜λ¦¬κ°€ λλ‚œ ν”„λ‘œλ―ΈμŠ€ 결과값을 λ°˜ν™˜ν•˜λ‹€. 

마치 ν”„λ‘œλ―ΈμŠ€ μ°Έκ°€μžλ“€μ΄ λ ˆμ΄μ‹±(race) κ²½μ£Όλ₯Ό ν•˜λŠ”κ²ƒμ„ λ– μ˜¬λ¦¬λ©΄ λœλ‹€.

μ•„λž˜ μ˜ˆμ‹œ μ½”λ“œλ₯Ό 보면 μ’€ 더 이해가 μˆ˜μ›”ν•  것이닀.

Promise.race
Promise.any
Promise.race
Promise.race


콜백 지μ˜₯을 이은 ν”„λ‘œλ―ΈμŠ€ 지μ˜₯

μžλ°”μŠ€ν¬λ¦½νŠΈ ν”„λ‘œλ―ΈμŠ€ 객체λ₯Ό 처음 μ†Œκ°œν• λ•Œ 콜백 지μ˜₯을 κ·Ήλ³΅ν•˜λŠ” μ‹ μ„ΈλŒ€μ˜ 문법이라고 μžμ‹ μžˆκ²Œ μ†Œκ°œν•˜μ˜€μœΌλ©΄μ„œ 콜백 지μ˜₯을 이은 ν”„λ‘œλ―ΈμŠ€ 지μ˜₯(Promise Hell)μ΄λΌλ‹ˆ ν—› μ›ƒμŒλ§Œ λ‚˜μ˜¬ 것이닀. 그런데 콜백 λͺ»μ§€μ•Šκ²Œ ν”„λ‘œλ―ΈμŠ€μ˜ then() λ©”μ„œλ“œκ°€ μ§€λ‚˜μΉ˜κ²Œ μ²΄μΈλ˜μ–΄ 반볡되면 μ½”λ“œκ°€ μž₯황해지고 가독성이 ꡉμž₯히 λ–¨μ–΄μ§ˆ 수 κ°€ μžˆλ‹€.

μ•„λž˜ μ˜ˆμ‹œ μ½”λ“œλŠ” fetch ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ κΉƒν—ˆλΈŒ APIμ—μ„œ μœ μ € 정보λ₯Ό κ°€μ Έμ˜€κ³ , then λ©”μ„œλ“œλ₯Ό μ—¬λŸ¬ 번 μ—°κ²°ν•˜μ—¬ μœ μ €λ“€μ˜ 둜그인 이름을 μ‰Όν‘œλ‘œ κ΅¬λΆ„ν•œ λ¬Έμžμ—΄λ‘œ λ§Œλ“€μ–΄ 좜λ ₯ν•˜λŠ” 비동기 μž‘μ—…μ„ μˆ˜ν–‰ν•œλ‹€. λ™μž‘ μžμ²΄λŠ” λ¬Έμ œκ°€ 없을 ν…Œμ§€λ§Œ, μ΄λŸ°μ‹μœΌλ‘œ then을 λŠ˜μ–΄λœ¨μ–΄ λ†“μœΌλ©΄ μ½”λ“œκ°€ 길어지고, 각 then λ©”μ„œλ“œκ°€ μ–΄λ–€ 값을 λ°˜ν™˜ν•˜λŠ”μ§€ νŒŒμ•…ν•˜κΈ° μ–΄λ ΅κ²Œ λœλ‹€. λ˜ν•œ, catch λ©”μ„œλ“œκ°€ λ§ˆμ§€λ§‰μ— ν•œ 번만 μ‚¬μš©λ˜μ–΄ 있기 λ•Œλ¬Έμ—, 쀑간에 λ°œμƒν•  수 μžˆλŠ” μ—λŸ¬λ‚˜ μ˜ˆμ™Έ 상황에 λŒ€μ‘ν•˜κΈ° μ–΄λ ΅λ‹€.

fetch("https://api.github.com/users")
  .then((response) => {
    if (response.ok) {
      return response.json();
    } else {
      throw new Error("Network Error");
    }
  })
  .then((users) => {
    return users.map((user) => user.login);
  })
  .then((logins) => {
    return logins.join(", ");
  })
  .then((result) => {
    console.log(result);
  })
  .catch((error) => {
    console.error(error);
  });

이λ₯Ό λ˜λ‹€μ‹œ κ·Ήλ³΅ν•˜κΈ° μœ„ν•΄ λ‚˜μ˜¨ μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ μ‹ μ„ΈλŒ€ 문법이 μžˆλŠ”λ° λ°”λ‘œ async/await ν‚€μ›Œλ“œμ΄λ‹€. async/await ν‚€μ›Œλ“œλŠ” ES8μ—μ„œ λ„μž…λœ 비동기 처리λ₯Ό μœ„ν•œ λ¬Έλ²•μœΌλ‘œ, ν”„λ‘œλ―ΈμŠ€λ₯Ό 기반으둜 ν•˜μ§€λ§Œ thenκ³Ό catch λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šκ³  비동기 μž‘μ—…μ„ μˆ˜ν–‰ν•  수 μžˆλ‹€. async/await ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜λ©΄ 비동기 μž‘μ—…μ„ 마치 동기 μž‘μ—…μ²˜λŸΌ μ“Έ 수 μžˆμ–΄μ„œ μ½”λ“œκ°€ κ°„κ²°ν•˜κ³  가독성이 μ’‹μ•„μ§€κ²Œ λœλ‹€.

try {
    const response = await fetch("");
    
    if (response.ok) {
      const users = await response.json();
      const logins = users.map((user) => user.login);
      const result = logins.join(", ");
      console.log(result);
    } else {
      throw new Error("Network Error");
    }
    
} catch (error) {
	console.error(error);
}

μ •μ‹  μ—†λŠ” ν”„λ‘œλ―ΈμŠ€ ν•Έλ“€λŸ¬λ₯Ό 없애버리고 1 라인으둜 비동기 μ½”λ“œλ“€μ„ κ΅¬μ„±ν–ˆμŒμ„ λ³Ό 수 μžˆλ‹€. async/await 문법에 λŒ€ν•΄μ„œ μžμ„Έν•œ μ‚¬μš©λ²•μ€ μ•„λž˜ ν¬μŠ€νŒ…μ„ μ°Έκ³ ν•˜κΈΈ λ°”λž€λ‹€.

 

πŸ“š μžλ°”μŠ€ν¬λ¦½νŠΈ Async/Await κ°œλ… & 문법 정볡

비동기 처리 방식 μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” μ‹±κΈ€ μŠ€λ ˆλ“œ ν”„λ‘œκ·Έλž˜λ°μ–Έμ–΄κΈ° λ•Œλ¬Έμ— λΉ„λ™κΈ°μ²˜λ¦¬κ°€ ν•„μˆ˜μ μ΄λ‹€. 비동기 μ²˜λ¦¬λŠ” κ·Έ κ²°κ³Όκ°€ μ–Έμ œ λ°˜ν™˜λ μ§€ μ•Œμˆ˜ μ—†κΈ° λ•Œλ¬Έμ— λ™κΈ°μ‹μœΌλ‘œ μ²˜λ¦¬ν•˜λŠ” 기법듀이

inpa.tistory.com


# 참고자료

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise

https://ko.javascript.info/promise-basics

https://velog.io/@ljinsk3/JavaScript-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%B2%98%EB%A6%AC-Promise-%EA%B0%9D%EC%B2%B4