Callback,Promise,async/await

ν•™μŠ΅ ν‚€μ›Œλ“œ

  • Callback ν•¨μˆ˜

  • Promise

  • async/await

Callback ν•¨μˆ˜

  • λ‹€λ₯Έν•¨μˆ˜μ˜ λ§€κ°œλ³€μˆ˜λ‘œ μ „λ‹¬λ˜λŠ” ν•¨μˆ˜λ₯Ό 의미

  • μ–΄λ–€ μž‘μ—…μ΄ λλ‚˜κ±°λ‚˜ μ΄λ²€νŠΈκ°€ λ°œμƒν–ˆμ„ λ•Œ ν˜ΈμΆœλ˜λŠ” ν•¨μˆ˜λ₯Ό 의미

  • 일반적으둜 비동기 ν•¨μˆ˜ μ²˜λ¦¬κ°€ λλ‚˜λ©΄ μ‹€ν–‰ν•  μž‘μ—…μœΌλ‘œ μ½œλ°±ν•¨μˆ˜λ₯Ό 전달

πŸ€” μ½œλ°±ν•¨μˆ˜κ°€ μ‚¬μš©λ˜λŠ” μ΄μœ λŠ”?

μžλ°”μŠ€ν¬λ¦½νŠΈλŠ” 동기적 λ°©μ‹μœΌλ‘œ ν•œλ²ˆμ— ν•œκ°€μ§€ 일만 μ²˜λ¦¬ν•œλ‹€. 즉, ν•¨μˆ˜κ°€ 호좜 λ˜λŠ” μˆœμ„œλŒ€λ‘œ 순차적으둜 μ½”λ“œκ°€ μ‹€ν–‰ λœλ‹€. κ·ΈλŸ¬λ‚˜, λ„€νŠΈμ›Œν¬ μš”μ²­κ³Ό 같이 μ‹œκ°„μ΄ κ±Έλ¦¬λŠ” μž‘μ—…μ„ μˆ˜ν–‰ ν•΄μ•Ό ν•˜κΈ° λ•Œλ¬Έμ— ν˜„μž¬ μ‹€ν–‰ 쀑인 μ½”λ“œκ°€ μ’…λ£Œ λ˜μ§€ μ•Šμ€ μƒνƒœλΌν•΄λ„ 기닀리지 μ•Šκ³  λ‹€μŒ μ½”λ“œλ₯Ό λ°”λ‘œ μ‹€ν–‰ν•˜λ„λ‘ 비동기 λ°©μ‹μœΌλ‘œ μ½”λ“œλ₯Ό μ‹€ν–‰μ‹œν‚¨λ‹€. 이와 같이 μˆœμ„œκ°€ 보μž₯ λ˜μ§€ μ•ŠλŠ” μƒν™©μ—μ„œ μˆœμ„œκ°€ 보μž₯λ˜κ±°λ‚˜, 비동기 ν•¨μˆ˜ μ²˜λ¦¬κ°€ λλ‚˜λ©΄ μ‹€ν–‰ν•  μž‘μ—…μ„ μ½œλ°±ν•¨μˆ˜μ— μ „λ‹¬ν•˜μ—¬ μ‚¬μš©ν•œλ‹€.

πŸ‘©πŸ»β€πŸ’» μ½œλ°±ν•¨μˆ˜ μ‚¬μš©ν•΄λ³΄μž

function task1() {
  console.log('첫번째둜 μ‹€ν–‰λ˜μ–΄μ•Ό ν•˜λŠ” ν•¨μˆ˜');
}

function task2() {
  // βœ… μˆœμ„œκ°€ 보μž₯λ˜μ§€ μ•ŠλŠ” ν•¨μˆ˜ 둜직이 μžˆλ‹€λ©΄?
  setTimeout(() => {
    console.log('λ‘λ²ˆμ§Έλ‘œ μ‹€ν–‰λ˜μ–΄μ•Ό ν•˜λŠ” ν•¨μˆ˜');
  }, 2000);
}

function task3() {
  console.log('μ„Έλ²ˆμ§Έλ‘œ μ‹€ν–‰λ˜μ–΄μ•Ό ν•˜λŠ” ν•¨μˆ˜');
}

function task4() {
  console.log('λ„€λ²ˆμ§Έλ‘œ μ‹€ν–‰λ˜μ–΄μ•Ό ν•˜λŠ” ν•¨μˆ˜');
}

task1();
task2();
task3();
task4();

μœ„μ˜ μ½”λ“œλ₯Ό 보면 task2 ν•¨μˆ˜λ‚΄λΆ€μ—λŠ” λΉ„λ™κΈ°λ‘œ λ™μž‘ν•˜λŠ” ν•¨μˆ˜ setTimeout μ‘΄μž¬ν•œλ‹€. λ‚΄κ°€ μ˜λ„ν–ˆλ˜κ±΄ task1 β†’ task2 β†’ task3 β†’ task4 순으둜 λ™μž‘ν•˜κΈΈ μ›ν–ˆλ‹€. κ·ΈλŸ¬λ‚˜ task1 β†’ task3 β†’ task4 β†’ task2 순으둜 λ™μž‘λ˜μ–΄ μ˜λ„ν•œ λ°©ν–₯κ³ΌλŠ” λ‹¬λžλ‹€. κ·Έλ ‡λ‹€λ©΄ μ½œλ°±ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•΄μ„œ μˆœμ„œλ₯Ό 보μž₯ν•˜λŠ” μ½”λ“œλ₯Ό μž‘μ„±ν•΄λ³΄μž!

function task1(callback) {
  console.log('첫번째둜 μ‹€ν–‰λ˜μ–΄μ•Ό ν•˜λŠ” ν•¨μˆ˜');
  callback();
}

function task2(callback) {
  // βœ… μˆœμ„œκ°€ 보μž₯λ˜μ§€ μ•ŠλŠ” ν•¨μˆ˜ 둜직이 μžˆλ‹€λ©΄?
  setTimeout(() => {
    console.log('λ‘λ²ˆμ§Έλ‘œ μ‹€ν–‰λ˜μ–΄μ•Ό ν•˜λŠ” ν•¨μˆ˜');
    callback();
  }, 2000);
}

function task3(callback) {
  console.log('μ„Έλ²ˆμ§Έλ‘œ μ‹€ν–‰λ˜μ–΄μ•Ό ν•˜λŠ” ν•¨μˆ˜');
  callback();
}

function task4(callback) {
  console.log('λ„€λ²ˆμ§Έλ‘œ μ‹€ν–‰λ˜μ–΄μ•Ό ν•˜λŠ” ν•¨μˆ˜');
  callback();
}

task1(() => {
  task2(() => {
    task3(() => {
      task4(() => {
        console.log('λͺ¨λ“  ν•¨μˆ˜ μ‹€ν–‰ μ™„λ£Œ!!');
      });
    });
  });
});

😱 μ½œλ°±μ§€μ˜₯(Callback hell)

좜처 : maxlchan.log
  • 비동기 ν•¨μˆ˜κ°€ μ²˜λ¦¬κ°€ λλ‚˜λ©΄ μ‹€ν–‰λ˜μ–΄μ•Ό ν•  μ½œλ°±ν•¨μˆ˜λ“€μ΄ μ€‘μ²©λ˜μ–΄ indent(λ“€μ—¬μ“°κΈ°)κ°€ 점점 κΉŠμ–΄μ§€λŠ” ν˜•νƒœλ‘œ 되고 이와같이 μ½”λ“œμ˜ 가독성이 μ•ˆμ’‹μ•„μ§€κ²Œ λ˜λŠ” 상황을 μ½œλ°±μ§€μ˜₯, Callback hell이라고 λΆ€λ₯Έλ‹€.

Promise

  • μ½œλ°±ν•¨μˆ˜μ˜ 단점을 λ³΄μ™„ν•˜λ©° 비동기 처리λ₯Ό 보닀 효율적으둜 μ²˜λ¦¬ν•˜κΈ° μœ„ν•΄ ES6 μΆ”κ°€λœ 문법

  • μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ 특수 객체 (비동기 ν•¨μˆ˜μ˜ κ²°κ³Όλ₯Ό λ‹΄κ³  μžˆλŠ” 객체)

  • λ‘κ°œμ˜ μ½œλ°±ν•¨μˆ˜λ₯Ό 인자둜 μ „λ‹¬λ°›λŠ”λ°, μž‘μ—…μ΄ μ„±κ³΅μ μœΌλ‘œ μ™„λ£Œλ˜μ—ˆμ„ λ•Œ κ²°κ³Όλ₯Ό λ°˜ν™˜ν•˜λŠ” resolve ν•¨μˆ˜μ™€ μž‘μ—…μ΄ μ‹€νŒ¨ν–ˆμ„λ–„ μ—λŸ¬λ₯Ό λ°˜ν™˜ν•˜λŠ” reject ν•¨μˆ˜κ°€ μžˆλ‹€.

κΈ°λ³Έ 문법

  • new ν‚€μ›Œλ“œλ₯Ό 톡해 생성

  • resolve, rejectλ₯Ό λ§€κ°œλ³€μˆ˜λ‘œ ν•˜λŠ” ν•¨μˆ˜ μ „λ‹¬λ°›λŠ”λ‹€.

    • resolve : 비동기 μ²˜λ¦¬κ°€ μ„±κ³΅ν–ˆμ„ λ•Œ ν˜ΈμΆœν•  ν•¨μˆ˜

    • reject : 비동기 μ²˜λ¦¬κ°€ μ‹€νŒ¨ν–ˆμ„ λ•Œ ν˜ΈμΆœν•  ν•¨μˆ˜

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

promise
  .then((res) => {
    console.log(res); // success
  })
  .catch((err) => {
    console.log(err); // fail
  });

πŸ”„ Promise 3κ°€μ§€ μƒνƒœ

pending(λŒ€κΈ°)

  • new Promise() λ©”μ„œλ“œλ‘œ ν˜ΈμΆœν•˜λ©΄ λŒ€κΈ° μƒνƒœκ°€ λœλ‹€.

  • 비동기 처리 둜직이 아직 μ™„λ£Œ λ˜μ§€ μ•Šμ€ μƒνƒœ

fulfilled(이행)

  • 비동기 μž‘μ—…μ΄ μ™„λ£Œλ˜μ–΄ ν”„λ‘œλ―ΈμŠ€κ°€ 결과값을 λ°˜ν™˜ν•΄μ€€ μƒνƒœ

  • then 을 톡해 μ²˜λ¦¬κ°’μ„ 전달받아 좔가적인 처리 κ°€λŠ₯

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('success'); // 비동기 ν•¨μˆ˜κ°€ μ™„λ£Œλ˜λ©΄ resolve()ν•¨μˆ˜ μ‹€ν–‰
  }, 2000);
});

promise.then((res) => {
  // resolve()의 κ²°κ³Όκ°’ μ½œλ°±ν•¨μˆ˜μ˜ 인자둜 전달받아 μ‚¬μš© κ°€λŠ₯
  console.log(res);
});

rejected(μ‹€νŒ¨)

  • 비동기 μž‘μ—…μ΄ μ‹€νŒ¨ν•˜κ±°λ‚˜ 였λ₯˜κ°€ λ°œμƒν•œ μƒνƒœ

  • μ‹€νŒ¨μƒνƒœκ°€ 되면 μ‹€νŒ¨ν•œ 이유λ₯Ό catch둜 받을 수 μžˆλ‹€.

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject('fail'); // 비동기 ν•¨μˆ˜κ°€ μ‹€νŒ¨ν•˜λ©΄ reject()ν•¨μˆ˜ μ‹€ν–‰
  }, 2000);
});

promise.catch((res) => {
  // reject()의 μ‹€νŒ¨μ΄μœ λ₯Ό 전달 λ°›μ•„ 좔가적인 처리 κ°€λŠ₯
  console.log(res);
});

⛓️ Promise 체이닝

  • Promise 객체의 λ©”μ„œλ“œλ₯Ό μ—°κ²°μ§€μ–΄ μ‚¬μš©ν•˜λŠ” 상황

promise
  .then((value) => {
    console.log(value);
  })
  .catch((error) => {
    console.log(error);
  });

😱 Promise hell도 μ‘΄μž¬ν•œλ‹€

  • μ•„λž˜ μ½”λ“œμ™€ 같이 then λ©”μ„œλ“œλ₯Ό 톡해 결과값을 인자둜 λ°›μ•„μ™€μ„œ μž‘μ—…μ„ μˆ˜ν–‰ν•˜κ³ , λ‹€μ‹œ then λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜κ³ , 또 then,then,... 와 같이 μž‘μ—…μ΄ 무수히 κΈΈμ–΄μ§€κΈ° λ•Œλ¬Έμ— μ½œλ°±μ§€μ˜₯에 이어 ν”„λ‘œλ―ΈμŠ€ ν—¬μ΄λΌλŠ” ν‘œν˜„λ„ μžˆλ‹€.

function sum(num) {
  const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
      if (typeof num === 'number') {
        resolve(num + 1);
      } else {
        reject('num이 μˆ«μžκ°€ μ•„λ‹™λ‹ˆλ‹€.');
      }
    }, 2000);
  });

  return promise;
}

sum(0).then((result) => {
  console.log(`κ²°κ³Ό : ${result}`);
  sum(result).then((result2) => {
    console.log(`κ²°κ³Ό : ${result2}`);
    sum(result2).then((result3) => {
      console.log(`κ²°κ³Ό : ${result3}`);
      sum(result3).then((result4) => {
        console.log(`κ²°κ³Ό : ${result4}`);
      });
    });
  });
});

πŸ”₯ return ν™œμš©ν•΄ Promise hell ν•΄κ²°ν•˜μž

  • return둜 promise객체λ₯Ό λ°˜ν™˜ν•΄μ„œ μ‚¬μš©ν•˜λ©΄ hellμ—μ„œ λ²—μ–΄λ‚  수 μžˆλ‹€.

sum(0)
  .then((result) => {
    console.log(`κ²°κ³Ό : ${result}`);
    return sum(result); // πŸ‘ˆπŸ» promise λ°˜ν™˜ν•˜λŠ” ν•¨μˆ˜
  })
  .then((result2) => {
    console.log(`κ²°κ³Ό : ${result2}`);
    return sum(result2);
  })
  .then((result3) => {
    console.log(`κ²°κ³Ό : ${result3}`);
    return sum(result3);
  })
  .then((result4) => {
    console.log(`κ²°κ³Ό : ${result4}`);
    return sum(result4);
  })
  .catch((err) => {
    console.log(`κ²°κ³Ό : ${err}`);
  });

Promise의 정적 λ©”μ„œλ“œ

  • μ—¬λŸ¬κ°œμ˜ 비동기 처리λ₯Ό λ³‘λ ¬μ μœΌλ‘œ μ²˜λ¦¬ν•  λ•Œ μ‚¬μš©ν•œλ‹€.

  • κ°κ°€μ˜ 비동기 호좜 μˆœμ„œκ°€ 상관 없을 λ•Œ μ‚¬μš©ν•œλ‹€.

  • μ£Όμ–΄μ§„ ν”„λ‘œλ―ΈμŠ€ 쀑 ν•˜λ‚˜κ°€ κ±°λΆ€ν•˜λŠ” 경우, 전체λ₯Ό reject μ²˜λ¦¬ν•œλ‹€.

function getEmoticon(icon) {
  const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
      if (typeof icon === 'string') {
        resolve(icon);
      } else {
        reject('이λͺ¨ν‹°μ½˜μ„ λ„£μ–΄μ£Όμ„Έμš”!');
      }
    }, 2000);
  });

  return promise;
}

Promise.all([getEmoticon('🍎'), getEmoticon('🍌'), getEmoticon('πŸ‰')]).then(
  (results) => {
    console.log(results); // [ '🍎', '🍌', 'πŸ‰' ]
  }
);

  • μ—¬λŸ¬κ°œμ˜ 비동기 처리 쀑 κ°€μž₯ λ¨Όμ € fulfilled 된 처리 κ²°κ³Όλ₯Ό κ°€μ Έμ˜¬ λ•Œ μ‚¬μš©

function getEmoticon(icon, ms) {
  const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
      if (typeof icon === 'string') {
        resolve(icon);
      } else {
        reject('이λͺ¨ν‹°μ½˜μ„ λ„£μ–΄μ£Όμ„Έμš”!');
      }
    }, ms);
  });

  return promise;
}

Promise.race([
  getEmoticon('🍎', 4000),
  getEmoticon('🍌', 2000),
  getEmoticon('πŸ‰', 1000),
]).then((results) => {
  console.log(results); // πŸ‰ 만 λ°˜ν™˜λ¨.
});

  • μ—¬λŸ¬κ°œμ˜ 비동기 μ²˜λ¦¬κ°€ λͺ¨λ‘ fulfilled λ‚˜ reject 된 처리 κ²°κ³Όλ₯Ό resolveν•˜λŠ” promiseλ₯Ό λ°˜ν™˜

function getEmoticon(icon, ms) {
  const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
      if (typeof icon === 'string') {
        resolve(icon);
      } else {
        reject('이λͺ¨ν‹°μ½˜μ„ λ„£μ–΄μ£Όμ„Έμš”!');
      }
    }, ms);
  });

  return promise;
}

Promise.allSettled([
  getEmoticon('🍎', 4000),
  getEmoticon(2, 2000),
  getEmoticon('πŸ‰', 1000),
]).then((results) => {
  console.log(results);
});

// 좜λ ₯κ²°κ³Ό
/**
[
  { status: 'fulfilled', value: '🍎' },
  { status: 'rejected', reason: '이λͺ¨ν‹°μ½˜μ„ λ„£μ–΄μ£Όμ„Έμš”!' },
  { status: 'fulfilled', value: 'πŸ‰' }
]
*/

async/await

  • Promiseλ₯Ό 쑰금 더 κ°„νŽΈν•˜κ³ , 가독성 μ’‹κ²Œ μ‚¬μš©ν•˜κΈ° μœ„ν•΄ λ‚˜μ˜¨ 문법

βœ… async/awaitλŠ” promise λ₯Ό 기반으둜 λ™μž‘ν•œλ‹€. promise의 then,catch,finally 후속 처리 λ©”μ„œλ“œμ— μ½œλ°±ν•¨μˆ˜λ₯Ό μ „λ‹¬ν•΄μ„œ 비동기 처리 κ²°κ³Όλ₯Ό μ²˜λ¦¬ν•  ν•„μš” 없이 마치 λ™κΈ°μ²˜λŸΌ ν”„λ‘œλ―ΈμŠ€λ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€.

기본문법

  • ν•¨μˆ˜ μ•žμ— asyncλ₯Ό 뢙이면 비동기적인 ν•¨μˆ˜μ΄κ³ , Promiseλ₯Ό λ°˜ν™˜ν•œλ‹€ 라고 μ„ μ–Έν•˜κ³ , λ°˜ν™˜ 값이 Promise μƒμ„±ν•¨μˆ˜κ°€ μ•„λ‹ˆμ–΄λ„ λ°˜ν™˜λ˜λŠ” 값을 Promise 객체에 λ„£λŠ”λ‹€.

const getData = async (url) => {
  const response = await fetch(url); // πŸ‘ˆπŸ» Promise의 μƒνƒœ 변경이 λ˜κΈ°μ „κΉŒμ§„ λ‹€μŒμ½”λ“œλŠ” μ‹€ν–‰λ˜μ§€ μ•ŠλŠ”λ‹€.
  const result = await response.json();
  console.log(result);
};
  • await은 asyncν•¨μˆ˜ μ•ˆμ—μ„œλ§Œ μ‚¬μš©ν•  수 있고, Promiseλ₯Ό λ°˜ν™˜ν•˜λŠ” ν•¨μˆ˜ μ•žμ— awaitλ₯Ό 뢙이면 Promiseκ°€ 성곡 μƒνƒœ λ˜λŠ” μ‹€νŒ¨ μƒνƒœλ‘œ λ°”λ€ŒκΈ° μ „κΉŒμ§€λŠ” λ‹€μŒ 연산을 ν•˜μ§€μ•Šμ•„ λ™κΈ°μ μœΌλ‘œ μž‘λ™λœλ‹€.

async/await μ˜ˆμ™Έμ²˜λ¦¬

  • Promise도 후속 μ²˜λ¦¬κ°€ λ§Žμ•„μ§ˆμˆ˜λ‘ then 내뢀에 μ½”λ“œκ°€ μ€‘μ²©λ˜λ©΄μ„œ μ½”λ“œ 흐름이 λ³΅μž‘ν•΄μ§€λŠ” 상황을 λ³΄μ•ˆν•˜κΈ° μœ„ν•΄ try/catch 으둜 κ°„λ‹¨νžˆ 처리 ν•  수 μžˆλ‹€.

const getData = async (url) => {
  try {
    const response = await fetch(url);
    const result = await response.json();
    console.log(result);
  } catch (error) {
    console.log(error);
  }
};

πŸ”— μ°Έκ³ 

Last updated