ํ‹ฐ์Šคํ† ๋ฆฌ ๋ทฐ

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ํ•˜๋‚˜์˜ ํŒจํ„ด์œผ๋กœ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ „ํ†ต์ ์ธ ์ฝœ๋ฐฑ ํŒจํ„ด์€ ์ฝœ๋ฐฑ ์ง€์˜ฅ(Callback Hell)๋กœ ์ธํ•ด ๊ฐ€๋…์„ฑ์ด ๋‚˜์˜๊ณ  ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ์ค‘ ๋ฐœ์ƒํ•œ ์—๋Ÿฌ์˜ ์ฒ˜๋ฆฌ๊ฐ€ ๊ณค๋ž€ํ•˜๋ฉฐ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ํ•œ๋ฒˆ์— ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐ๋„ ํ•œ๊ณ„๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

 

ES6์—์„œ๋Š” ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ๋˜ ๋‹ค๋ฅธ ํŒจํ„ด์œผ๋กœ ํ”„๋กœ๋ฏธ์Šค(Promise)๋ฅผ ๋„์ž…ํ–ˆ์œผ๋ฉฐ ์ด๋Š” ์ „ํ†ต์ ์ธ ์ฝœ๋ฐฑ ํŒจํ„ด์ด ๊ฐ€์ง„ ๋‹จ์ ์„ ๋ณด์™„ํ•˜๋ฉฐ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ์‹œ์ ์„ ๋ช…ํ™•ํ•˜๊ฒŒ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.


๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ์ฝœ๋ฐฑ ํŒจํ„ด์˜ ๋‹จ์ 

์ฝœ๋ฐฑ ์ง€์˜ฅ(Callbak Hell)

๋น„๋™๊ธฐ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ํ•จ์ˆ˜ ๋‚ด๋ถ€์˜ ๋น„๋™๊ธฐ๋กœ ๋™์ž‘ํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ์™„๋ฃŒ๋˜์ง€ ์•Š์•˜๋‹ค ํ•ด๋„ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  ์ฆ‰์‹œ ์ข…๋ฃŒ๋ฉ๋‹ˆ๋‹ค.

  • ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋Š” ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ์™ธ๋ถ€์— ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์—†์Œ
  • ์ƒ์œ„ ์Šค์ฝ”ํ”„์˜ ๋ณ€์ˆ˜์— ํ• ๋‹นํ•  ์ˆ˜๋„ ์—†์Œ

์˜ˆ๋ฅผ ๋“ค์–ด get ํ•จ์ˆ˜ ๋‚ด๋ถ€์˜ onload ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ๋น„๋™๊ธฐ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

 

let todos;

// GET ์š”์ฒญ์„ ์œ„ํ•œ ๋น„๋™๊ธฐ ํ•จ์ˆ˜
const get = url => {
  const xhr = new XMLHttpRequest();
  xhr.open('GET', url);
  xhr.send();

  xhr.onload = () => {
    if (xhr.status === 200) {
      // โ‘  ์„œ๋ฒ„์˜ ์‘๋‹ต์„ ์ƒ์œ„ ์Šค์ฝ”ํ”„์˜ ๋ณ€์ˆ˜์— ํ• ๋‹นํ•œ๋‹ค.
      todos = JSON.parse(xhr.response);
    } else {
      console.error(`${xhr.status} ${xhr.statusText}`);
    }
  };
};

// id๊ฐ€ 1์ธ post๋ฅผ ์ทจ๋“
get('https://jsonplaceholder.typicode.com/posts/1');
console.log(todos); // โ‘ก undefined

 

  • onload ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋Š” get ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์บ์น˜ํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์—†์Œ
  • onload ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ํ”„๋กœํผํ‹ฐ์— ๋ฐ”์ธ๋”ฉํ•œ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋Š” ์–ธ์ œ๋‚˜ console.log(todos)๊ฐ€ ์ข…๋ฃŒํ•œ ์ดํ›„์— ํ˜ธ์ถœ๋จ

๋”ฐ๋ผ์„œ ๋น„๋™๊ธฐ ํ•จ์ˆ˜์˜ ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ(์„œ๋ฒ„์˜ ์‘๋‹ต ๋“ฑ)์— ๋Œ€ํ•œ ํ›„์† ์ฒ˜๋ฆฌ๋Š” ๋น„๋™๊ธฐ ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋•Œ ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋ฅผ ๋ฒ”์šฉ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๋น„๋™๊ธฐ ํ•จ์ˆ˜์— ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ์— ๋Œ€ํ•œ ํ›„์† ์ฒ˜๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ ์ž…๋‹ˆ๋‹ค.

 

ํ•„์š”์— ๋”ฐ๋ผ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๊ฐ€ ์„ฑ๊ณตํ•˜๋ฉด ํ˜ธ์ถœ๋  ์ฝœ๋ฐฑ ํ•จ์ˆ˜์™€ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๊ฐ€ ์‹คํŒจํ•˜๋ฉด ํ˜ธ์ถœ๋  ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

// GET ์š”์ฒญ์„ ์œ„ํ•œ ๋น„๋™๊ธฐ ํ•จ์ˆ˜
const get = (url, successCallback, failureCallback) => {
  const xhr = new XMLHttpRequest();
  xhr.open('GET', url);
  xhr.send();

  xhr.onload = () => {
    if (xhr.status === 200) {
      // ์„œ๋ฒ„์˜ ์‘๋‹ต์„ ์ฝœ๋ฐฑ ํ•จ์ˆ˜์— ์ธ์ˆ˜๋กœ ์ „๋‹ฌํ•˜๋ฉด์„œ ํ˜ธ์ถœํ•˜์—ฌ ์‘๋‹ต์— ๋Œ€ํ•œ ํ›„์† ์ฒ˜๋ฆฌ๋ฅผ ํ•œ๋‹ค.
      successCallback(JSON.parse(xhr.response));
    } else {
      // ์—๋Ÿฌ ์ •๋ณด๋ฅผ ์ฝœ๋ฐฑ ํ•จ์ˆ˜์— ์ธ์ˆ˜๋กœ ์ „๋‹ฌํ•˜๋ฉด์„œ ํ˜ธ์ถœํ•˜์—ฌ ์—๋Ÿฌ ์ฒ˜๋ฆฌ๋ฅผ ํ•œ๋‹ค.
      failureCallback(xhr.status);
    }
  };
};

// id๊ฐ€ 1์ธ post๋ฅผ ์ทจ๋“
// ์„œ๋ฒ„์˜ ์‘๋‹ต์— ๋Œ€ํ•œ ํ›„์† ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ๋น„๋™๊ธฐ ํ•จ์ˆ˜์ธ get์— ์ „๋‹ฌํ•ด์•ผ ํ•œ๋‹ค.
get('https://jsonplaceholder.typicode.com/posts/1', console.log, console.error);
/*
{
  "userId": 1,
  "id": 1,
  "title": "sunt aut facere ...",
  "body": "quia et suscipit ..."
}
*/

 

ํ•˜์ง€๋งŒ ์ด๋Ÿฌํ•œ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋Š” ์ฝœ๋ฐฑ ์ง€์˜ฅ์— ๋น ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฝœ๋ฐฑ ์ง€์˜ฅ์ด๋ž€ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ์— ๋Œ€ํ•œ ํ›„์† ์ฒ˜๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๋น„๋™๊ธฐ ํ•จ์ˆ˜๊ฐ€ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ€์ง€๊ณ  ๋˜๋‹ค์‹œ ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ด์•ผ ํ•œ๋‹ค๋ฉด ์ฝœ๋ฐฑ ํ•จ์ˆ˜ ํ˜ธ์ถœ์ด ์ค‘์ฒฉ๋˜์–ด ๋ณต์žก๋„๊ฐ€ ๋†’์•„์ง€๋Š” ํ˜„์ƒ์ด ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

 

get('/step1', a => {
  get(`/step2/${a}`, b => {
    get(`/step3/${b}`, c => {
      get(`/step4/${c}`, d => {
        console.log(d);
      });
    });
  });
});

 

์—๋Ÿฌ ์ฒ˜๋ฆฌ์˜ ํ•œ๊ณ„ 

๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ์ฝœ๋ฐฑ ํŒจํ„ด์˜ ๋ฌธ์ œ์  ์ค‘์—์„œ ๊ฐ€์žฅ ์‹ฌ๊ฐํ•œ ๊ฒƒ์€ ์—๋Ÿฌ ์ฒ˜๋ฆฌ๊ฐ€ ๊ณค๋ž€ํ•˜๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์—๋Ÿฌ๋Š” ํ˜ธ์ถœ์ž ๋ฐฉํ–ฅ(์ฝœ ์Šคํƒ์˜ ์•„๋ž˜ ๋ฐฉํ–ฅ)์œผ๋กœ ์ „ํŒŒ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์•„๋ž˜์˜ ์˜ˆ์‹œ ๊ฐ™์€ ์ƒํ™ฉ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

 

try {
  setTimeout(() => { throw new Error('Error!'); }, 1000);
} catch (e) {
  // ์—๋Ÿฌ๋ฅผ ์บ์น˜ํ•˜์ง€ ๋ชปํ•œ๋‹ค
  console.error('์บ์น˜ํ•œ ์—๋Ÿฌ', e);
}
  1. ๋น„๋™๊ธฐ ํ•จ์ˆ˜์ธ setTimeout์ด ํ˜ธ์ถœ๋˜๋ฉด setTimeout ํ•จ์ˆ˜์˜ ์‹คํ–‰ ์ปจํ…์ŠคํŠธ๊ฐ€ ์ƒ์„ฑ๋˜์–ด ์ฝœ ์Šคํƒ์— ํ‘ธ์‹œ๋˜์–ด ์‹คํ–‰๋จ
  2. setTimeout์€ ๋น„๋™๊ธฐ ํ•จ์ˆ˜์ด๋ฏ€๋กœ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ๊ฒƒ์„ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  ์ฆ‰์‹œ ์ข…๋ฃŒ๋˜์–ด ์ฝœ ์Šคํƒ์—์„œ ์ œ๊ฑฐ๋จ
  3. ์ดํ›„ ํƒ€์ด๋จธ๊ฐ€ ๋งŒ๋ฃŒ๋˜๋ฉด setTimeout ํ•จ์ˆ˜์˜ ์ฝœ๋ฐฑํ•จ์ˆ˜๋Š” ํƒœ์Šคํฌ ํ๋กœ ํ‘ธ์‹œ๋˜๊ณ  ์ฝœ ์Šคํƒ์ด ๋น„๋ฉด ํ‘ธ์‹œ๋˜์–ด ์‹คํ–‰๋จ
  4. ์ด๋•Œ, ์‹คํ–‰๋˜๋Š” ์ฝœ๋ฐฑ ํ•จ์ˆ˜์˜ ํ˜ธ์ถœ์ž๋Š” setTimeout์ด ์•„๋‹ˆ๋ฏ€๋กœ ์—๋Ÿฌ๋Š” catch ๋ธ”๋ก์—์„œ ์บ์น˜๋˜์ง€ ์•Š์Œ

๋”ฐ๋ผ์„œ ์ฝœ๋ฐฑ ์ง€์˜ฅ์ด๋‚˜ ์—๋Ÿฌ ์ฒ˜๋ฆฌ์˜ ๋ฌธ์ œ๋ฅผ ๊ทน๋ณตํ•˜๊ธฐ ์œ„ํ•ด ES6์—์„œ ํ”„๋กœ๋ฏธ์Šค๊ฐ€ ๋„์ž…๋˜์—ˆ์Šต๋‹ˆ๋‹ค.


ํ”„๋กœ๋ฏธ์Šค์˜ ์ƒ์„ฑ

Promise ์ƒ์„ฑ์ž ํ•จ์ˆ˜๋ฅผ new ์—ฐ์‚ฐ์ž์™€ ํ•จ๊ป˜ ํ˜ธ์ถœํ•˜๋ฉด Promise ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. (Promise๋Š” ํ‘œ์ค€ ๋นŒํŠธ์ธ ๊ฐ์ฒด)

 

Promise ์ƒ์„ฑ์ž ํ•จ์ˆ˜๋Š” ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ฝœ๋ฐฑ ํ•จ์ˆ˜(executor ํ•จ์ˆ˜)๋ฅผ ์ธ์ˆ˜๋กœ ์ „๋‹ฌ๋ฐ›๋Š”๋ฐ ์ด ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋Š” resolve์™€ reject ํ•จ์ˆ˜๋ฅผ ์ธ์ˆ˜๋กœ ์ „๋‹ฌ๋ฐ›์œผ๋ฉฐ ๋‚ด๋ถ€์—์„œ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

  • resolve :  ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๊ฐ€ ์„ฑ๊ณตํ•˜๋ฉด ์ฝœ๋ฐฑ ํ•จ์ˆ˜์˜ ์ธ์ˆ˜๋กœ ์ „๋‹ฌ๋ฐ›์€ resolve ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœ
  • reject : ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๊ฐ€ ์‹คํŒจํ•˜๋ฉด reject ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœ
// GET ์š”์ฒญ์„ ์œ„ํ•œ ๋น„๋™๊ธฐ ํ•จ์ˆ˜
const promiseGet = url => {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url);
    xhr.send();

    xhr.onload = () => {
      if (xhr.status === 200) {
        // ์„ฑ๊ณต์ ์œผ๋กœ ์‘๋‹ต์„ ์ „๋‹ฌ๋ฐ›์œผ๋ฉด resolve ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.
        resolve(JSON.parse(xhr.response));
      } else {
        // ์—๋Ÿฌ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด reject ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.
        reject(new Error(xhr.status));
      }
    };
  });
};

// promiseGet ํ•จ์ˆ˜๋Š” ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
promiseGet('https://jsonplaceholder.typicode.com/posts/1');

 

 

ํ”„๋กœ๋ฏธ์Šค๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ˜„์žฌ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๊ฐ€ ์–ด๋–ป๊ฒŒ ์ง„ํ–‰๋˜๊ณ  ์žˆ๋Š”์ง€๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ์ƒํƒœ(state)์ •๋ณด๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค.

 

ํ”„๋กœ๋ฏธ์Šค ์ƒํƒœ ์ •๋ณด ์˜๋ฏธ ์ƒํƒœ ๋ณ€๊ฒฝ ์กฐ๊ฑด
pending ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๊ฐ€ ์•„์ง ์ˆ˜ํ–‰๋˜์ง€ ์•Š์€ ์ƒํƒœ ํ”„๋กœ๋ฏธ์Šค๊ฐ€ ์ƒ์„ฑ๋œ ์งํ›„ ๊ธฐ๋ณธ ์ƒํƒœ
fulfilled ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๊ฐ€ ์ˆ˜ํ–‰๋œ ์ƒํƒœ(์„ฑ๊ณต) resolve ํ•จ์ˆ˜ ํ˜ธ์ถœ
rejected ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๊ฐ€ ์ˆ˜ํ–‰๋œ ์ƒํƒœ(์‹คํŒจ) reject ํ•จ์ˆ˜ ํ˜ธ์ถœ

 

์ƒ์„ฑ๋œ ์งํ›„์˜ ํ”„๋กœ๋ฏธ์Šค๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ pending ์ƒํƒœ์ž…๋‹ˆ๋‹ค. ์ดํ›„ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๊ฐ€ ์ˆ˜ํ–‰๋˜๋ฉด ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ์— ๋”ฐ๋ผ resolve ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ด fulfilled ์ƒํƒœ๋กœ ๋ณ€๊ฒฝ / reject ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ด rejected ์ƒํƒœ๋กœ ๋ณ€๊ฒฝ๋˜๋ฉฐ ์ด๋ฅผ settled ์ƒํƒœ๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

 

์ด๋Ÿฌํ•œ settled ์ƒํƒœ๋Š” fulfilled / rejected ์ƒ๊ด€์—†์ด pending์ด ์•„๋‹Œ ์ƒํƒœ๋กœ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๊ฐ€ ์ˆ˜ํ–‰๋œ ์ƒํƒœ๋ฅผ ๋งํ•˜๋ฉฐ ์ผ๋‹จ settled ์ƒํƒœ๊ฐ€ ๋˜๋ฉด ๋”๋Š” ๋‹ค๋ฅธ ์ƒํƒœ๋กœ ๋ณ€ํ™”ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

 

 

์œ„ ๊ทธ๋ฆผ์ฒ˜๋Ÿผ ํ”„๋กœ๋ฏธ์Šค๋Š” ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ์ƒํƒœ์™€ ๋”๋ถˆ์–ด ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ(result)๋„ ์ƒํƒœ๋กœ ๊ฐ€์ง‘๋‹ˆ๋‹ค.

 

 

์ด์ฒ˜๋Ÿผ ํ”„๋กœ๋ฏธ์Šค๋Š” ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ์ƒํƒœ์™€ ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค.

  • ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๊ฐ€ ์„ฑ๊ณตํ•˜๋ฉด ํ”„๋กœ๋ฏธ์Šค๋Š” pending ์ƒํƒœ์—์„œ fulfilled ์ƒํƒœ๋กœ ๋ณ€ํ™”ํ•˜๋ฉฐ ๊ฒฐ๊ณผ๊ฐ’ 1์„ ๊ฐ€์ง
  • ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๊ฐ€ ์‹คํŒจํ•˜๋ฉด ํ”„๋กœ๋ฏธ์Šค๋Š” pending ์ƒํƒœ์—์„œ rejected ์ƒํƒœ๋กœ ๋ณ€ํ™”ํ•˜๋ฉฐ ๊ฒฐ๊ณผ๊ฐ’ Error ๊ฐ์ฒด๋ฅผ ๊ฐ€์ง

ํ”„๋กœ๋ฏธ์Šค์˜ ํ›„์† ์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ

ํ”„๋กœ๋ฏธ์Šค์˜ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ์ƒํƒœ๊ฐ€ ๋ณ€ํ™”ํ•˜๋ฉด ์ด์— ๋”ฐ๋ฅธ ํ›„์† ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๊ธฐ ์œ„ํ•ด ํ”„๋กœ๋ฏธ์Šค๋Š” ํ›„์† ๋ฉ”์„œ๋“œ then, catch, finally๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ํ”„๋กœ๋ฏธ์Šค์˜ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ์ƒํƒœ๊ฐ€ ๋ณ€ํ™”ํ•˜๋ฉด ํ›„์† ์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ์— ์ธ์ˆ˜๋กœ ์ „๋‹ฌํ•œ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๊ฐ€ ์„ ํƒ์ ์œผ๋กœ ํ˜ธ์ถœ๋˜๋ฉฐ, ํ›„์† ์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ์˜ ์ฝœ๋ฐฑ ํ•จ์ˆ˜์— ํ”„๋กœ๋ฏธ์Šค์˜ ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๊ฐ€ ์ธ์ˆ˜๋กœ ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค.

 

์ด๋Ÿฌํ•œ ํ›„์† ์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ๋Š” ๋ชจ๋‘ ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ, ๋น„๋™๊ธฐ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

 

Promise.prototype.then

then ๋ฉ”์„œ๋“œ๋Š” ๋‘ ๊ฐœ์˜ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์ธ์ˆ˜๋กœ ์ „๋‹ฌ๋ฐ›์Šต๋‹ˆ๋‹ค.

  • ์ฒซ ๋ฒˆ์งธ ์ฝœ๋ฐฑ  ํ•จ์ˆ˜๋Š” ํ”„๋กœ๋ฏธ์Šค๊ฐ€ fulfilled ์ƒํƒœ(resolve ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋œ ์ƒํƒœ)๊ฐ€ ๋˜๋ฉด ํ˜ธ์ถœ๋˜๋ฉฐ ํ”„๋กœ๋ฏธ์Šค์˜ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ์ธ์ˆ˜๋กœ ์ „๋‹ฌ๋ฐ›์Šต๋‹ˆ๋‹ค.
  • ๋‘ ๋ฒˆ์งธ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋Š” ํ”„๋กœ๋ฏธ์Šค๊ฐ€ rejected ์ƒํƒœ(reject ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋œ ์ƒํƒœ)๊ฐ€ ๋˜๋ฉด ํ˜ธ์ถœ๋˜๋ฉฐ ํ”„๋กœ๋ฏธ์Šค์˜ ์—๋Ÿฌ๋ฅผ ์ธ์ˆ˜๋กœ ์ „๋‹ฌ๋ฐ›์Šต๋‹ˆ๋‹ค.
// fulfilled
new Promise(resolve => resolve('fulfilled'))
  .then(v => console.log(v), e => console.error(e)); // fulfilled

// rejected
new Promise((_, reject) => reject(new Error('rejected')))
  .then(v => console.log(v), e => console.error(e)); // Error: rejected

 

then ๋ฉ”์„œ๋“œ๋Š” ์–ธ์ œ๋‚˜ ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ then ๋ฉ”์„œ๋“œ์˜ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๊ฐ€ ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด ๊ทธ ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜ํ•˜๊ณ , ์ฝœ๋ฐฑ ํ•จ์ˆ˜๊ฐ€ ํ”„๋กœ๋ฏธ์Šค๊ฐ€ ์•„๋‹Œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋ฉด ๊ทธ ๊ฐ’์„ ์•”๋ฌต์ ์œผ๋กœ resolve ๋˜๋Š” rejectํ•˜์—ฌ ํ”„๋กœ๋ฏธ์Šค๋ฅผ ์ƒ์„ฑํ•ด ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

 

Promise.prototype.catch

catch ๋ฉ”์„œ๋“œ๋Š” ํ•œ ๊ฐœ์˜ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์ธ์ˆ˜๋กœ ์ „๋‹ฌ๋ฐ›์œผ๋ฉฐ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋Š” ํ”„๋กœ๋ฏธ์Šค๊ฐ€ rejected ์ƒํƒœ์ธ ๊ฒฝ์šฐ๋งŒ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ, catch ๋ฉ”์„œ๋“œ๋Š” then(undefined, onRejected)๊ณผ ๋™์ผํ•˜๊ฒŒ ๋™์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์–ธ์ œ๋‚˜ ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

 

// rejected
new Promise((_, reject) => reject(new Error('rejected')))
  .catch(e => console.log(e)); // Error: rejected
  
// rejected
new Promise((_, reject) => reject(new Error('rejected')))
  .then(undefined, e => console.log(e)); // Error: rejected

 

 

Promise.prototype.finally

finally ๋ฉ”์„œ๋“œ๋Š” ํ•œ ๊ฐœ์˜ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์ธ์ˆ˜๋กœ ์ „๋‹ฌ๋ฐ›์Šต๋‹ˆ๋‹ค. finally ๋ฉ”์„œ๋“œ์˜ ์ฝœ๋ฐฑ ํ•ฉ์ˆ˜๋Š” ํ”„๋กœ๋ฏธ์Šค์˜ ์„ฑ๊ณต(fulfilled) ๋˜๋Š” ์‹คํŒจ(rejected)์™€ ์ƒ๊ด€์—†์ด ๋ฌด์กฐ๊ฑด ํ•œ ๋ฒˆ ํ˜ธ์ถœ๋˜๋ฉฐ ์–ธ์ œ๋‚˜ ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํ”„๋กœ๋ฏธ์Šค์˜ ์ƒํƒœ์™€ ์ƒ๊ด€์—†์ด ๊ณตํ†ต์ ์œผ๋กœ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•  ์ฒ˜๋ฆฌ ๋‚ด์šฉ์ด ์žˆ์„ ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

 

new Promise(() => {})
  .finally(() => console.log('finally')); // finally

 


ํ”„๋กœ๋ฏธ์Šค์˜ ์—๋Ÿฌ ์ฒ˜๋ฆฌ

๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ์ฝœ๋ฐฑ ํŒจํ„ด๊ณผ ๋‹ฌ๋ฆฌ ํ”„๋กœ๋ฏธ์Šค๋Š” ์—๋Ÿฌ๋ฅผ ๋ฌธ์ œ์—†์ด ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

์•„๋ž˜ ์˜ˆ์ œ์˜ ๋น„๋™๊ธฐ ํ•จ์ˆ˜ get์€ ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ then, catch, finally ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ›„์† ์ฒ˜๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

 

const promiseGet = url => {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url);
    xhr.send();

    xhr.onload = () => {
      if (xhr.status === 200) {
        // ์„ฑ๊ณต์ ์œผ๋กœ ์‘๋‹ต์„ ์ „๋‹ฌ๋ฐ›์œผ๋ฉด resolve ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.
        resolve(JSON.parse(xhr.response));
      } else {
        // ์—๋Ÿฌ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด reject ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.
        reject(new Error(xhr.status));
      }
    };
  });
};

// promiseGet ํ•จ์ˆ˜๋Š” ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
promiseGet('https://jsonplaceholder.typicode.com/posts/1')
  .then(res => console.log(res))
  .catch(err => console.error(err))
  .finally(() => console.log('Bye!'));

 

์ด๋•Œ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ์—์„œ ๋ฐœ์ƒํ•œ ์—๋Ÿฌ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

 

then ๋ฉ”์„œ๋“œ์˜ ๋‘ ๋ฒˆ์งธ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋กœ ์—๋Ÿฌ ์ฒ˜๋ฆฌ

const wrongUrl = 'https://jsonplaceholder.typicode.com/XXX/1';

// ๋ถ€์ ์ ˆํ•œ URL์ด ์ง€์ •๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.
promiseGet(wrongUrl).then(
  res => console.log(res),
  err => console.error(err)
); // Error: 404

// ์ฒซ ๋ฒˆ์งธ ์ฝœ๋ฐฑ ํ•จ์ˆ˜์˜ ์—๋Ÿฌ ์บ์น˜ X
promiseGet('https://jsonplaceholder.typicode.com/todos/1').then(
  res => console.xxx(res),
  err => console.error(err)
); // ๋‘ ๋ฒˆ์งธ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋Š” ์ฒซ ๋ฒˆ์งธ ์ฝœ๋ฐฑ ํ•จ์ˆ˜์—์„œ ๋ฐœ์ƒํ•œ ์—๋Ÿฌ๋ฅผ ์บ์น˜ํ•˜์ง€ ๋ชปํ•œ๋‹ค.
  • then ๋ฉ”์„œ๋“œ์˜ ๋‘ ๋ฒˆ์งธ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋Š” ์ฒซ ๋ฒˆ์งธ ์ฝœ๋ฐฑ ํ•จ์ˆ˜์—์„œ ๋ฐœ์ƒํ•œ ์—๋Ÿฌ๋ฅผ ์บ์น˜ํ•˜์ง€ ๋ชปํ•˜๊ณ  ์ฝ”๋“œ๊ฐ€ ๋ณต์žกํ•ด์ ธ์„œ ๊ฐ€๋…์„ฑ์ด ์ข‹์ง€ ์•Š๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ์Œ

ํ”„๋กœ๋ฏธ์Šค์˜ ํ›„์† ์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ catch๋ฅผ ์‚ฌ์šฉํ•ด ์—๋Ÿฌ ์ฒ˜๋ฆฌ

const wrongUrl = 'https://jsonplaceholder.typicode.com/XXX/1';

// ๋ถ€์ ์ ˆํ•œ URL์ด ์ง€์ •๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.
promiseGet(wrongUrl)
  .then(res => console.log(res))
  .catch(err => console.error(err)); // Error: 404
  
const wrongUrl = 'https://jsonplaceholder.typicode.com/XXX/1';

// ๋ถ€์ ์ ˆํ•œ URL์ด ์ง€์ •๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.
promiseGet(wrongUrl)
  .then(res => console.log(res))
  .then(undefined, err => console.error(err)); // Error: 404

// then ๋ฉ”์„œ๋“œ ๋‚ด๋ถ€ ์—๋Ÿฌ๋„ ์ฒ˜๋ฆฌ
promiseGet('https://jsonplaceholder.typicode.com/todos/1')
  .then(res => console.xxx(res))
  .catch(err => console.error(err)); // TypeError: console.xxx is not a function
  • catch ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ๋‚ด๋ถ€์ ์œผ๋กœ then(undefined, onRejected)์„ ํ˜ธ์ถœํ•˜์—ฌ ์ฒ˜๋ฆฌ๋จ
  • catch ๋ฉ”์„œ๋“œ๋ฅผ ๋ชจ๋“  then ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ ์ดํ›„์— ํ˜ธ์ถœํ•˜๋ฉด ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ์—์„œ ๋ฐœ์ƒํ•œ ์—๋Ÿฌ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ then ๋ฉ”์„œ๋“œ ๋‚ด๋ถ€์—์„œ ๋ฐœ์ƒํ•œ ์—๋Ÿฌ๊นŒ์ง€ ๋ชจ๋‘ ์บ์น˜ ๊ฐ€๋Šฅ
  • then ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•œ ์—๋Ÿฌ ์ฒ˜๋ฆฌ์— ๋น„ํ•ด ๊ฐ€๋…์„ฑ์ด ์ข‹๊ณ  ๋ช…ํ™•ํ•˜๊ธฐ ๋•Œ๋ฌธ์— catch ๋ฉ”์„œ๋“œ๋กœ ์—๋Ÿฌ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ๊ถŒ์žฅ๋จ

ํ”„๋กœ๋ฏธ์Šค ์ฒด์ด๋‹

ํ”„๋กœ๋ฏธ์Šค๋Š” then, catch, filnally ํ›„์† ์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์ฝœ๋ฐฑ ์ง€์˜ฅ์„ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜ ์˜ˆ์ œ๋Š” then -> then -> catch ์ˆœ์„œ๋กœ ํ›„์† ์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

 

const url = 'https://jsonplaceholder.typicode.com';

// id๊ฐ€ 1์ธ post์˜ userId๋ฅผ ์ทจ๋“
promiseGet(`${url}/posts/1`)
  // ์ทจ๋“ํ•œ post์˜ userId๋กœ user ์ •๋ณด๋ฅผ ์ทจ๋“
  .then(({ userId }) => promiseGet(`${url}/users/${userId}`))
  .then(userInfo => console.log(userInfo))
  .catch(err => console.error(err));

 

์ด์ฒ˜๋Ÿผ then, catch, filnally ํ›„์† ์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ๋Š” ์–ธ์ œ๋‚˜ ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฏ€๋กœ ์—ฐ์†์ ์œผ๋กœ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ด๋ฅผ ํ”„๋กœ๋ฏธ์Šค ์ฒด์ด๋‹(promise chaining)์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

 

ํ”„๋กœ๋ฏธ์Šค๋Š” ํ”„๋กœ๋ฏธ์Šค ์ฒด์ด๋‹์„ ํ†ตํ•ด ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ์ „๋‹ฌ๋ฐ›์•„ ํ›„์† ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋ฏ€๋กœ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ์ฝœ๋ฐฑ ํŒจํ„ด์—์„œ ๋ฐœ์ƒํ•˜๋˜ ์ฝœ๋ฐฑ ์ง€์˜ฅ์ด ๋ฐœ์ƒํ•˜์ง€๋Š” ์•Š์ง€๋งŒ ํ”„๋กœ๋ฏธ์Šค๋„ ์ฝœ๋ฐฑ ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ ๊ฐ€๋…์„ฑ์ด ์ข‹์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

 

๋”ฐ๋ผ์„œ ์ด ๋ฌธ์ œ๋Š” ES8์—์„œ ๋„์ž…๋œ async/await์„ ํ†ตํ•ด ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 


ํ”„๋กœ๋ฏธ์Šค์˜ ์ •์  ๋ฉ”์„œ๋“œ

Promise๋Š” ์ฃผ๋กœ ์ƒ์„ฑ์ž ํ•จ์ˆ˜๋กœ ์‚ฌ์šฉ๋˜์ง€๋งŒ ํ•จ์ˆ˜๋„ ๊ฐ์ฒด์ด๋ฏ€๋กœ ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์”๋‹ˆ๋‹ค. Promise๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด 5๊ฐ€์ง€ ์ •์  ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

 

Promise.resolve / Promise.reject

Promise.resolve์™€ Promise.reject ๋ฉ”์„œ๋“œ๋Š” ์ด๋ฏธ ์กด์žฌํ•˜๋Š” ๊ฐ’์„ ๋ž˜ํ•‘ํ•˜์—ฌ ํ”„๋กœ๋ฏธ์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

  • Promise.resolve : ์ธ์ˆ˜๋กœ ์ „๋‹ฌ๋ฐ›์€ ๊ฐ’์„ resolveํ•˜๋Š” ํ”„๋กœ๋ฏธ์Šค๋ฅผ ์ƒ์„ฑ
  • Promise.reject : ์ธ์ˆ˜๋กœ ์ „๋‹ฌ๋ฐ›์€ ๊ฐ’์„ rejectํ•˜๋Š” ํ”„๋กœ๋ฏธ์Šค๋ฅผ ์ƒ์„ฑ
// ๋ฐฐ์—ด์„ resolveํ•˜๋Š” ํ”„๋กœ๋ฏธ์Šค๋ฅผ ์ƒ์„ฑ 1
const resolvedPromise = Promise.resolve([1, 2, 3]);
resolvedPromise.then(console.log); // [1, 2, 3]

// ์œ„์™€ ๋™์ผ
const resolvedPromise = new Promise(resolve => resolve([1, 2, 3]));
resolvedPromise.then(console.log); // [1, 2, 3]


// ์—๋Ÿฌ ๊ฐ์ฒด๋ฅผ rejectํ•˜๋Š” ํ”„๋กœ๋ฏธ์Šค๋ฅผ ์ƒ์„ฑ1
const rejectedPromise = Promise.reject(new Error('Error!'));
rejectedPromise.catch(console.log); // Error: Error!

// ์œ„์™€ ๋™์ผ
const rejectedPromise = new Promise((_, reject) => reject(new Error('Error!')));
rejectedPromise.catch(console.log); // Error: Error!

 

Promise.all

Promise.all ๋ฉ”์„œ๋“œ๋Š” ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ๋ชจ๋‘ ๋ณ‘๋ ฌ(parallel) ์ฒ˜๋ฆฌํ•  ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

 

Promise.all ๋ฉ”์„œ๋“œ๋Š” ํ”„๋กœ๋ฏธ์Šค๋ฅผ ์š”์†Œ๋กœ ๊ฐ–๋Š” ๋ฐฐ์—ด ๋“ฑ์˜ ์ดํ„ฐ๋Ÿฌ๋ธ”์„ ์ธ์ˆ˜๋กœ ์ „๋‹ฌ๋ฐ›์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ „๋‹ฌ๋ฐ›์€ ๋ชจ๋“  ํ”„๋กœ๋ฏธ์Šค๊ฐ€ ๋ชจ๋‘ fulfilled ์ƒํƒœ๊ฐ€ ๋˜๋ฉด ๋ชจ๋“  ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ๋ฐฐ์—ด์— ์ €์žฅํ•ด ์ƒˆ๋กœ์šด ํ”„๋กœ๋ฏธ์Šค๋ฅผ ์ „๋‹ฌ๋ฐ›์Šต๋‹ˆ๋‹ค.

 

// ์ฒ˜๋ฆฌ ์ˆœ์„œ๊ฐ€ ๋ณด์žฅ
const requestData1 = () => new Promise(resolve => setTimeout(() => resolve(1), 3000));
const requestData2 = () => new Promise(resolve => setTimeout(() => resolve(2), 2000));
const requestData3 = () => new Promise(resolve => setTimeout(() => resolve(3), 1000));

Promise.all([requestData1(), requestData2(), requestData3()])
  .then(console.log) // [ 1, 2, 3 ] ⇒ ์•ฝ 3์ดˆ ์†Œ์š”
  .catch(console.error);
  
// rejected๋˜๋ฉด ์ฆ‰์‹œ ์ข…๋ฃŒ
Promise.all([
  new Promise((_, reject) => setTimeout(() => reject(new Error('Error 1')), 3000)),
  new Promise((_, reject) => setTimeout(() => reject(new Error('Error 2')), 2000)),
  new Promise((_, reject) => setTimeout(() => reject(new Error('Error 3')), 1000))
])
  .then(console.log)
  .catch(console.log); // Error: Error 3
 
// ํ”„๋กœ๋ฏธ์Šค๋กœ ๋ž˜ํ•‘
Promise.all([
  1, // => Promise.resolve(1)
  2, // => Promise.resolve(2)
  3  // => Promise.resolve(3)
])
  .then(console.log) // [1, 2, 3]
  .catch(console.log);

 

  • ์ฒ˜๋ฆฌ ์ˆœ์„œ๊ฐ€ ๋ณด์žฅ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ฒซ ๋ฒˆ์งธ ํ”„๋กœ๋ฏธ์Šค๊ฐ€ resolveํ•œ ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๋ถ€ํ„ฐ ์ฐจ๋ก€๋Œ€๋กœ ๋ฐฐ์—ด์— ์ €์žฅ
  • ์ธ์ˆ˜๋กœ ์ „๋‹ฌ๋ฐ›์€ ๋ฐฐ์—ด์˜ ํ”„๋กœ๋ฏธ์Šค๊ฐ€ ํ•˜๋‚˜๋ผ๋„ rejected ์ƒํƒœ๊ฐ€ ๋˜๋ฉด ๋‚˜๋จธ์ง€ ํ”„๋กœ๋ฏธ์Šค ์ƒํƒœ๊ฐ€ fulfilled ์ƒํƒœ๊ฐ€ ๋˜๋Š” ๊ฒƒ์„ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  ์ฆ‰์‹œ ์ข…๋ฃŒ
  • ์ธ์ˆ˜๋กœ ์ „๋‹ฌ๋ฐ›์€ ์ดํ„ฐ๋Ÿฌ๋ธ” ์š”์†Œ๊ฐ€ ํ”„๋กœ๋ฏธ์Šค๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ Promise.resolve ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ํ”„๋กœ๋ฏธ์Šค๋กœ ๋ž˜ํ•‘

 

Promise.race

Promise.race ๋ฉ”์„œ๋“œ๋Š” Promise.all ๋ฉ”์„œ๋“œ์™€ ๋™์ผํ•˜๊ฒŒ ํ”„๋กœ๋ฏธ์Šค๋ฅผ ์š”์†Œ๋กœ ๊ฐ–๋Š” ๋ฐฐ์—ด ๋“ฑ์˜ ์ดํ„ฐ๋Ÿฌ๋ธ”์„ ์ธ์ˆ˜๋กœ ์ „๋‹ฌ๋ฐ›์ง€๋งŒ, Promise.all ๋ฉ”์„œ๋“œ์™€ ๋‹ฌ๋ฆฌ ๋ชจ๋“  ํ”„๋กœ๋ฏธ์Šค๊ฐ€ fulfilled ์ƒํƒœ๊ฐ€ ๋˜๋Š” ๊ฒƒ์„ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๊ฐ€์žฅ ๋จผ์ € fulfilled ์ƒํƒœ๊ฐ€ ๋œ ํ”„๋กœ๋ฏธ์Šค์˜ ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ resolveํ•˜๋Š” ์ƒˆ๋กœ์šด ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

 

Promise.race([
  new Promise(resolve => setTimeout(() => resolve(1), 3000)), // 1
  new Promise(resolve => setTimeout(() => resolve(2), 2000)), // 2
  new Promise(resolve => setTimeout(() => resolve(3), 1000)) // 3
])
  .then(console.log) // 3
  .catch(console.log);
  
// rejected ์ƒํƒœ
Promise.race([
  new Promise((_, reject) => setTimeout(() => reject(new Error('Error 1')), 3000)),
  new Promise((_, reject) => setTimeout(() => reject(new Error('Error 2')), 2000)),
  new Promise((_, reject) => setTimeout(() => reject(new Error('Error 3')), 1000))
])
  .then(console.log)
  .catch(console.log); // Error: Error 3
  • ์ธ์ˆ˜๋กœ ์ „๋‹ฌ๋œ ํ”„๋กœ๋ฏธ์Šค๊ฐ€ ํ•˜๋‚˜๋ผ๋„ rejected ์ƒํƒœ๊ฐ€ ๋˜๋ฉด ์—๋Ÿฌ๋ฅผ rejectํ•˜๋Š” ์ƒˆ๋กœ์šด ํ”„๋กœ๋ฏธ์Šค๋ฅผ ์ฆ‰์‹œ ๋ฐ˜ํ™˜

 

Promise.allSettled

Promise.allSettled ๋ฉ”์„œ๋“œ๋Š” ํ”„๋กœ๋ฏธ์Šค๋ฅผ ์š”์†Œ๋กœ ๊ฐ–๋Š” ๋ฐฐ์—ด ๋“ฑ์˜ ์ดํ„ฐ๋Ÿฌ๋ธ”์„ ์ธ์ˆ˜๋กœ ์ „๋‹ฌ๋ฐ›์œผ๋ฉฐ ์ „๋‹ฌ๋ฐ›์€ ํ”„๋กœ๋ฏธ์Šค๊ฐ€ ๋ชจ๋‘ settled ์ƒํƒœ๊ฐ€ ๋˜๋ฉด ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ๋ฐฐ์—ด๋กœ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

 

Promise.allSettled([
  new Promise(resolve => setTimeout(() => resolve(1), 2000)),
  new Promise((_, reject) => setTimeout(() => reject(new Error('Error!')), 1000))
]).then(console.log);
/*
[
  {status: "fulfilled", value: 1},
  {status: "rejected", reason: Error: Error! at <anonymous>:3:54}
]
*/

 

์ด์ฒ˜๋Ÿผ Promise.allSettled ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฐ˜ํ™˜ํ•œ ๋ฐฐ์—ด์—๋Š” fulfilled ๋˜๋Š” rejected ์ƒํƒœ์™€๋Š” ์ƒ๊ด€์—†์ด Promise.allSettled ๋ฉ”์„œ๋“œ๊ฐ€ ์ธ์ˆ˜๋กœ ์ „๋‹ฌ๋ฐ›์€ ๋ชจ๋“  ํ”„๋กœ๋ฏธ์Šค๋“ค์˜ ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๊ฐ€ ๋ชจ๋‘ ๋‹ด๊ฒจ ์žˆ์Šต๋‹ˆ๋‹ค.

  • fulfilled ์ƒํƒœ : ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ์ƒํƒœ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” status ํ”„๋กœํผํ‹ฐ์™€ ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” value ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ€์ง
  • rejected ์ƒํƒœ : ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ์ƒํƒœ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” status ํ”„๋กœํผํ‹ฐ์™€ ์—๋Ÿฌ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” reason ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ€์ง

๋งˆ์ดํฌ๋กœํƒœ์Šคํฌ ํ

ํ”„๋กœ๋ฏธ์Šค์˜ ํ›„์† ์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ์˜ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋Š” ํƒœ์Šคํฌ ํ๊ฐ€ ์•„๋‹ˆ๋ผ ๋งˆ์ดํฌ๋กœํƒœ์Šคํฌ ํ์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.

  • ํ…Œ์Šคํฌ ํ์™€๋Š” ๋ณ„๋„์˜ ํ
  • ํ”„๋กœ๋ฏธ์Šค์˜ ํ›„์† ์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ์™€ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๊ฐ€ ์ผ์‹œ ์ €์žฅ
  • ํƒœ์Šคํฌ ํ๋ณด๋‹ค ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’์Œ

ํ”„๋กœ๋ฏธ์Šค์˜ ํ›„์† ์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ ์™ธ์˜ ๋น„๋™๊ธฐ ํ•จ์ˆ˜์˜ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋‚˜ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋Š” ํƒœ์Šคํฌ ํ์— ์ผ์‹œ ์ €์žฅ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์•„๋ž˜ ์˜ˆ์ œ๋Š” 2 -> 3 -> 1์˜ ์ˆœ์œผ๋กœ ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค.

setTimeout(() => console.log(1), 0);

Promise.resolve()
  .then(() => console.log(2))
  .then(() => console.log(3));

 

์ด์ฒ˜๋Ÿผ ์ด๋ฒคํŠธ ๋ฃจํ”„๋Š” ์ฝœ ์Šคํƒ์ด ๋น„๋ฉด ๋จผ์ € ๋งˆ์ดํฌ๋กœํƒœ์Šคํฌ ํ์—์„œ ๋Œ€๊ธฐํ•˜๊ณ  ์žˆ๋Š” ํ•จ์ˆ˜๋ฅผ ๊ฐ€์ ธ์™€ ์‹คํ–‰ํ•˜๊ณ  ์ดํ›„ ๋งˆ์ดํฌ๋กœํƒœ์Šคํฌ ํ๊ฐ€ ๋น„๋ฉด ํƒœ์Šคํฌ ํ์—์„œ ๋Œ€๊ธฐํ•˜๊ณ  ์žˆ๋Š” ํ•จ์ˆ˜๋ฅผ ๊ฐ€์ ธ์™€ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.


fetch

fetch ํ•จ์ˆ˜๋Š” XMLHttpRequest ๊ฐ์ฒด์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ HTTP ์š”์ฒญ ์ „์†ก ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ Web API ์ด๋ฉฐ

XMLHttpRequest ๊ฐ์ฒด๋ณด๋‹ค ์‚ฌ์šฉ๋ฒ•์ด ๊ฐ„๋‹จํ•˜๊ณ  ํ”„๋กœ๋ฏธ์Šค๋ฅผ ์ง€์›ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ์ฝœ๋ฐฑ ํŒจํ„ด์˜ ๋‹จ์ ์—์„œ

์ž์œ ๋กญ์Šต๋‹ˆ๋‹ค.

 

const promise = fetch(url, [, options])

 

fetch ํ•จ์ˆ˜์—๋Š” HTTP ์š”์ฒญ์„ ์ „์†กํ•  URL๊ณผ HTTP ์š”์ฒญ ๋ฉ”์„œ๋“œ, HTTP ์š”์ฒญ ํ—ค๋”, ํŽ˜์ด๋กœ๋“œ ๋“ฑ์„ ์„ค์ •ํ•œ ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ•˜๋ฉฐ HTTP ์‘๋‹ต์„ ๋‚˜ํƒ€๋‚ด๋Š” Response ๊ฐ์ฒด๋ฅผ ๋ž˜ํ•‘ํ•œ Promise ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

 

fetch('https://jsonplaceholder.typicode.com/todos/1')
  .then(response => console.log(response));

 

๋”ฐ๋ผ์„œ ํ›„์† ์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ then์„ ํ†ตํ•ด ํ”„๋กœ๋ฏธ์Šค๊ฐ€ resolveํ•œ Response ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌ๋ฐ›์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ Response๊ฐ์ฒด๋Š” HTTP ์‘๋‹ต์„ ๋‚˜ํƒ€๋‚ด๋Š” ๋‹ค์–‘ํ•œ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

 

fetch ํ•จ์ˆ˜์˜ ์—๋Ÿฌ ์ฒ˜๋ฆฌ

fetch ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ์—๋Ÿฌ ์ฒ˜๋ฆฌ์— ์ฃผ์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • fetch ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ”„๋กœ๋ฏธ์Šค๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ 404๋‚˜ 500์™€ ๊ฐ™์€ HTTP ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ด๋„ ์—๋Ÿฌ๋ฅผ rejectํ•˜์ง€ ์•Š๊ณ  ๋ถˆ๋ฆฌ์–ธ ํƒ€์ž…์˜ ok ์ƒํƒœ๋ฅผ false๋กœ ์„ค์ •ํ•œ Response ๊ฐ์ฒด๋ฅผ resolveํ•จ
  • ์˜คํ”„๋ผ์ธ ๋“ฑ์˜ ๋„คํŠธ์›Œํฌ ์žฅ์• ๋‚˜ CORS ์—๋Ÿฌ์— ์˜ํ•ด ์š”์ฒญ์ด ์™„๋ฃŒ๋˜์ง€ ๋ชปํ•œ ๊ฒฝ์šฐ์—๋งŒ ํ”„๋กœ๋ฏธ์Šค๋ฅผ rejectํ•จ

๋”ฐ๋ผ์„œ fetch ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด fetch ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜ํ™˜ํ•œ ํ”„๋กœ๋ฏธ์Šค๊ฐ€ resolveํ•œ ๋ถˆ๋ฆฌ์–ธ ํƒ€์ž…์˜ ok ์ƒํƒœ๋ฅผ ํ™•์ธํ•ด ๋ช…์‹œ์ ์œผ๋กœ ์—๋Ÿฌ๋ฅผ ์ฒ˜๋ฆฌํ•  ํ•„์š”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

 

const wrongUrl = 'https://jsonplaceholder.typicode.com/XXX/1';

// ๋ถ€์ ์ ˆํ•œ URL์ด ์ง€์ •๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— 404 Not Found ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.
fetch(wrongUrl)
  // response๋Š” HTTP ์‘๋‹ต์„ ๋‚˜ํƒ€๋‚ด๋Š” Response ๊ฐ์ฒด๋‹ค.
  .then(response => {
    if (!response.ok) throw new Error(response.statusText);
    return response.json();
  })
  .then(todo => console.log(todo))
  .catch(err => console.error(err));

*axios๋Š” ๋ชจ๋“  HTTP ์—๋Ÿฌ๋ฅผ rejectํ•˜๋Š” ํ”„๋กœ๋ฏธ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜์—ฌ ๋ชจ๋“  ์—๋Ÿฌ๋ฅผ catch์—์„œ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด ํŽธ๋ฆฌํ•˜๋ฉฐ ์ธํ„ฐ์…‰ํ„ฐ,

์š”์ฒญ ์„ค์ • ๋“ฑ fetch๋ณด๋‹ค ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ์„ ์ง€์›ํ•จ

 

GET ์š”์ฒญ

 

request.get('https://jsonplaceholder.typicode.com/todos/1')
  .then(response => {
    if (!response.ok) throw new Error(response.statusText);
    return response.json();
  })
  .then(todos => console.log(todos))
  .catch(err => console.error(err));
// {userId: 1, id: 1, title: "delectus aut autem", completed: false}

 

POST ์š”์ฒญ

 

request.post('https://jsonplaceholder.typicode.com/todos', {
  userId: 1,
  title: 'JavaScript',
  completed: false
}).then(response => {
    if (!response.ok) throw new Error(response.statusText);
    return response.json();
  })
  .then(todos => console.log(todos))
  .catch(err => console.error(err));
// {userId: 1, title: "JavaScript", completed: false, id: 201}

 

PATCH ์š”์ฒญ

 

request.patch('https://jsonplaceholder.typicode.com/todos/1', {
  completed: true
}).then(response => {
    if (!response.ok) throw new Error(response.statusText);
    return response.json();
  })
  .then(todos => console.log(todos))
  .catch(err => console.error(err));
// {userId: 1, id: 1, title: "delectus aut autem", completed: true}

 

DELETE ์š”์ฒญ

 

request.delete('https://jsonplaceholder.typicode.com/todos/1')
  .then(response => {
    if (!response.ok) throw new Error(response.statusText);
    return response.json();
  })
  .then(todos => console.log(todos))
  .catch(err => console.error(err));
// {}

[์ถœ์ฒ˜] ๋ชจ๋˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ Deep Dive

https://wikibook.co.kr/mjs/

 

๋ชจ๋˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ Deep Dive: ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ๊ธฐ๋ณธ ๊ฐœ๋…๊ณผ ๋™์ž‘ ์›๋ฆฌ

269๊ฐœ์˜ ๊ทธ๋ฆผ๊ณผ ์›๋ฆฌ๋ฅผ ํŒŒํ—ค์น˜๋Š” ์„ค๋ช…์œผ๋กœ ‘์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ๊ธฐ๋ณธ ๊ฐœ๋…๊ณผ ๋™์ž‘ ์›๋ฆฌ’๋ฅผ ์ดํ•ดํ•˜์ž! ์›นํŽ˜์ด์ง€์˜ ๋‹จ์ˆœํ•œ ๋ณด์กฐ ๊ธฐ๋Šฅ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ์ œํ•œ์ ์ธ ์šฉ๋„๋กœ ํƒœ์–ด๋‚œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ๊ณผ๋„

wikibook.co.kr