๐Ÿš€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ: Promise์™€ async/await ์™„๋ฒฝ ๊ฐ€์ด๋“œ (2025๋…„ ์ตœ์‹  ํŠธ๋ Œ๋“œ) ๐Ÿš€

์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - ๐Ÿš€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ: Promise์™€ async/await ์™„๋ฒฝ ๊ฐ€์ด๋“œ (2025๋…„ ์ตœ์‹  ํŠธ๋ Œ๋“œ) ๐Ÿš€

 

 

์•ˆ๋…•, ์ฝ”๋”ฉ ์นœ๊ตฌ๋“ค! ์˜ค๋Š˜์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ๊ฝƒ์ด๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋Š” ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์— ๋Œ€ํ•ด ํ•จ๊ป˜ ์•Œ์•„๋ณผ ๊ฑฐ์•ผ. 2025๋…„ ํ˜„์žฌ, ์›น ๊ฐœ๋ฐœ์—์„œ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋Š” ์„ ํƒ์ด ์•„๋‹Œ ํ•„์ˆ˜๊ฐ€ ๋˜์—ˆ์–ด. ํŠนํžˆ Promise์™€ async/await๋Š” ๋ชจ๋˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ํ•ต์‹ฌ ๊ธฐ๋Šฅ์ด์ง€! ๐Ÿ˜Ž

์ด ๊ธ€์„ ํ†ตํ•ด ์ฝœ๋ฐฑ ์ง€์˜ฅ์—์„œ ๋ฒ—์–ด๋‚˜ ๊น”๋”ํ•˜๊ณ  ํšจ์œจ์ ์ธ ๋น„๋™๊ธฐ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋งˆ์Šคํ„ฐํ•  ์ˆ˜ ์žˆ์„ ๊ฑฐ์•ผ. ์žฌ๋Šฅ๋„ท์—์„œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐœ๋ฐœ ์žฌ๋Šฅ์„ ๊ณต์œ ํ•˜๊ฑฐ๋‚˜ ๊ตฌ๋งคํ•  ๋•Œ๋„ ์ด๋Ÿฐ ์ง€์‹์€ ์ •๋ง ์ค‘์š”ํ•˜๊ฑฐ๋“ ! ์ž, ์ด์ œ ์‹œ์ž‘ํ•ด๋ณผ๊นŒ? ๐ŸŽฎ

๐Ÿ“š ๋ชฉ์ฐจ

  1. ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด๋ž€?
  2. ์ฝœ๋ฐฑ ํ•จ์ˆ˜์™€ ์ฝœ๋ฐฑ ์ง€์˜ฅ
  3. Promise ์™„๋ฒฝ ์ดํ•ดํ•˜๊ธฐ
  4. async/await ๋งˆ์Šคํ„ฐํ•˜๊ธฐ
  5. ์‹ค์ „ ์˜ˆ์ œ๋กœ ๋ฐฐ์šฐ๋Š” ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ
  6. 2025๋…„ ์ตœ์‹  ๋น„๋™๊ธฐ ํŒจํ„ด๊ณผ ํŠธ๋ Œ๋“œ
  7. ์„ฑ๋Šฅ ์ตœ์ ํ™” ํŒ
  8. ๋งˆ๋ฌด๋ฆฌ ๋ฐ ์ถ”๊ฐ€ ์ž๋ฃŒ

1. ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด๋ž€? ๐Ÿค”

๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด ๋ญ”์ง€ ์นœ๊ตฌ์—๊ฒŒ ์„ค๋ช…ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ด๋ณผ๊นŒ? ์•„์ฃผ ๊ฐ„๋‹จํ•ด! ๋น„๋™๊ธฐ๋Š” '๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  ๋‹ค๋ฅธ ์ผ์„ ํ•˜๋Š” ๊ฒƒ'์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋ผ.

์˜ˆ๋ฅผ ๋“ค์–ด๋ณผ๊ฒŒ. ๋„Œ ์นดํŽ˜์—์„œ ์ปคํ”ผ๋ฅผ ์ฃผ๋ฌธํ–ˆ์–ด. ๋™๊ธฐ์  ์„ธ๊ณ„์—์„  ์ปคํ”ผ๊ฐ€ ๋‚˜์˜ฌ ๋•Œ๊นŒ์ง€ ์นด์šดํ„ฐ ์•ž์—์„œ ๊ผผ์ง ๋ชปํ•˜๊ณ  ๊ธฐ๋‹ค๋ ค์•ผ ํ•ด. ๊ทผ๋ฐ ๋น„๋™๊ธฐ์  ์„ธ๊ณ„์—์„ ? ์ฃผ๋ฌธํ•˜๊ณ  ์ง„๋™๋ฒจ์„ ๋ฐ›์€ ๋‹ค์Œ, ์ž๋ฆฌ์— ์•‰์•„์„œ ๋‹ค๋ฅธ ์ผ(๋…ธํŠธ๋ถ ์ผœ๊ธฐ, ์นœ๊ตฌ๋ž‘ ๋Œ€ํ™”ํ•˜๊ธฐ ๋“ฑ)์„ ํ•  ์ˆ˜ ์žˆ์ง€! ์ปคํ”ผ๊ฐ€ ์ค€๋น„๋˜๋ฉด ๋ฒจ์ด ์šธ๋ฆฌ๊ณ , ๊ทธ๋•Œ ๊ฐ€์„œ ์ปคํ”ผ๋ฅผ ๋ฐ›์œผ๋ฉด ๋ผ. ์ด๊ฒŒ ๋ฐ”๋กœ ๋น„๋™๊ธฐ์•ผ! ๐Ÿ‘

1.1 ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์™€ ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ ์–ธ์–ด์•ผ. ์ฆ‰, ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์˜ ์ž‘์—…๋งŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด. ๊ทธ๋Ÿฐ๋ฐ ์–ด๋–ป๊ฒŒ ์—ฌ๋Ÿฌ ์ž‘์—…์„ ๋™์‹œ์— ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ผ๊นŒ? ๊ทธ ๋น„๋ฐ€์€ ๋ฐ”๋กœ '์ด๋ฒคํŠธ ๋ฃจํ”„'์— ์žˆ์–ด!

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋Ÿฐํƒ€์ž„ Call Stack ์‹คํ–‰ ์ค‘์ธ ์ฝ”๋“œ Web APIs Callback Queue Event Loop ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ด๋ฒคํŠธ ๋ฃจํ”„ ๋ชจ๋ธ

์ด๋ฒคํŠธ ๋ฃจํ”„๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๋น„๋™๊ธฐ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ํ•ต์‹ฌ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด์•ผ. ์œ„ ๊ทธ๋ฆผ์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋“ฏ์ด, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ์ฝœ ์Šคํƒ์—์„œ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๊ณ , ๋น„๋™๊ธฐ ์ž‘์—…์€ Web API๋กœ ๋„˜๊ฒจ. ์ž‘์—…์ด ์™„๋ฃŒ๋˜๋ฉด ์ฝœ๋ฐฑ ํ์— ๋“ค์–ด๊ฐ€๊ณ , ์ด๋ฒคํŠธ ๋ฃจํ”„๊ฐ€ ์ฝœ ์Šคํƒ์ด ๋น„์—ˆ์„ ๋•Œ ์ฝœ๋ฐฑ์„ ์‹คํ–‰ํ•ด์ฃผ๋Š” ๊ฑฐ์ง€! ๐Ÿ˜Š

1.2 ๋™๊ธฐ vs ๋น„๋™๊ธฐ ์ฝ”๋“œ ๋น„๊ต

๋™๊ธฐ ์ฝ”๋“œ ์˜ˆ์‹œ:


console.log("์ž‘์—… 1 ์‹œ์ž‘");
// ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋Š” ์ž‘์—…
for (let i = 0; i < 1000000000; i++) {
  // ๋ฌด๊ฑฐ์šด ๊ณ„์‚ฐ
}
console.log("์ž‘์—… 1 ์™„๋ฃŒ");
console.log("์ž‘์—… 2 ์‹œ์ž‘");
        

๋น„๋™๊ธฐ ์ฝ”๋“œ ์˜ˆ์‹œ:


console.log("์ž‘์—… 1 ์‹œ์ž‘");
// ๋น„๋™๊ธฐ ์ž‘์—… (์‹œ๊ฐ„์ด ๊ฑธ๋ฆฌ์ง€๋งŒ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š์Œ)
setTimeout(() => {
  console.log("์ž‘์—… 1 ์™„๋ฃŒ");
}, 2000);
console.log("์ž‘์—… 2 ์‹œ์ž‘"); // ์ž‘์—… 1์ด ๋๋‚˜๊ธฐ ์ „์— ์‹คํ–‰๋จ!
        

๋น„๋™๊ธฐ ์ฝ”๋“œ์˜ ์žฅ์ ์€ ๋ญ˜๊นŒ? ๋ฐ”๋กœ ํšจ์œจ์„ฑ์ด์•ผ! ํŠนํžˆ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ƒํ™ฉ์—์„œ ๋น›์„ ๋ฐœํ•˜์ง€:

  1. ๋„คํŠธ์›Œํฌ ์š”์ฒญ (API ํ˜ธ์ถœ, ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ)
  2. ํŒŒ์ผ ์‹œ์Šคํ…œ ์ž‘์—… (ํŒŒ์ผ ์ฝ๊ธฐ/์“ฐ๊ธฐ)
  3. ํƒ€์ด๋จธ ๋ฐ ์ธํ„ฐ๋ฒŒ (setTimeout, setInterval)
  4. ์‚ฌ์šฉ์ž ์ž…๋ ฅ ์ฒ˜๋ฆฌ (์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ)
  5. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ฟผ๋ฆฌ

2. ์ฝœ๋ฐฑ ํ•จ์ˆ˜์™€ ์ฝœ๋ฐฑ ์ง€์˜ฅ ๐Ÿ˜ฑ

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

์ฝœ๋ฐฑ ํ•จ์ˆ˜๋Š” ๋งˆ์น˜ ํ”ผ์ž๋ฅผ ์ฃผ๋ฌธํ•œ ํ›„ "ํ”ผ์ž๊ฐ€ ์ค€๋น„๋˜๋ฉด ์ด ๋ฒˆํ˜ธ๋กœ ์ „ํ™”ํ•ด์ฃผ์„ธ์š”"๋ผ๊ณ  ๋งํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์•„. ๋„ˆ๋Š” ์ „ํ™”๊ฐ€ ์˜ฌ ๋•Œ๊นŒ์ง€ ๋‹ค๋ฅธ ์ผ์„ ํ•  ์ˆ˜ ์žˆ๊ณ , ์ „ํ™”(์ฝœ๋ฐฑ)๊ฐ€ ์˜ค๋ฉด ๊ทธ๋•Œ ํ”ผ์ž๋ฅผ ๋ฐ›์œผ๋Ÿฌ ๊ฐ€๋Š” ๊ฑฐ์ง€! ๐Ÿ•

2.1 ๊ฐ„๋‹จํ•œ ์ฝœ๋ฐฑ ์˜ˆ์ œ


function downloadFile(url, callback) {
  console.log(`${url}์—์„œ ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ ์‹œ์ž‘...`);
  
  // ๋น„๋™๊ธฐ ์ž‘์—… ์‹œ๋ฎฌ๋ ˆ์ด์…˜ (์‹ค์ œ๋กœ๋Š” fetch ๋“ฑ์„ ์‚ฌ์šฉ)
  setTimeout(() => {
    const fileName = url.split('/').pop();
    console.log(`${fileName} ๋‹ค์šด๋กœ๋“œ ์™„๋ฃŒ!`);
    callback(fileName); // ๋‹ค์šด๋กœ๋“œ ์™„๋ฃŒ ํ›„ ์ฝœ๋ฐฑ ์‹คํ–‰
  }, 2000);
}

downloadFile('https://example.com/photo.jpg', (fileName) => {
  console.log(`๋‹ค์šด๋กœ๋“œํ•œ ${fileName}์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.`);
});

console.log("๋‹ค์šด๋กœ๋“œ ๋ช…๋ น ํ›„ ์ฆ‰์‹œ ์‹คํ–‰๋˜๋Š” ์ฝ”๋“œ");
    

์œ„ ์ฝ”๋“œ์˜ ์‹คํ–‰ ์ˆœ์„œ๋Š” ์–ด๋–ป๊ฒŒ ๋ ๊นŒ? ๐Ÿค”

  1. "https://example.com/photo.jpg์—์„œ ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ ์‹œ์ž‘..." ์ถœ๋ ฅ
  2. "๋‹ค์šด๋กœ๋“œ ๋ช…๋ น ํ›„ ์ฆ‰์‹œ ์‹คํ–‰๋˜๋Š” ์ฝ”๋“œ" ์ถœ๋ ฅ
  3. 2์ดˆ ํ›„ "photo.jpg ๋‹ค์šด๋กœ๋“œ ์™„๋ฃŒ!" ์ถœ๋ ฅ
  4. "๋‹ค์šด๋กœ๋“œํ•œ photo.jpg์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค." ์ถœ๋ ฅ

์ด์ฒ˜๋Ÿผ ๋น„๋™๊ธฐ ์ž‘์—…์€ ์ฝ”๋“œ์˜ ์‹คํ–‰ ์ˆœ์„œ๊ฐ€ ์ž‘์„ฑ๋œ ์ˆœ์„œ์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์–ด. ์ด๊ฒŒ ๋ฐ”๋กœ ๋น„๋™๊ธฐ์˜ ํŠน์ง•์ด์ง€!

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

๊ทธ๋Ÿฐ๋ฐ ๋น„๋™๊ธฐ ์ž‘์—…์ด ์—ฌ๋Ÿฌ ๊ฐœ ์ค‘์ฒฉ๋˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ? ๋ฐ”๋กœ ์ฝœ๋ฐฑ ์ง€์˜ฅ(Callback Hell)์ด ํŽผ์ณ์ ธ! ๐Ÿ˜ฑ

์ฒซ ๋ฒˆ์งธ ๋น„๋™๊ธฐ ์ž‘์—…() ๋‘ ๋ฒˆ์งธ ๋น„๋™๊ธฐ ์ž‘์—…() ์„ธ ๋ฒˆ์งธ ๋น„๋™๊ธฐ ์ž‘์—…() ๋„ค ๋ฒˆ์งธ ๋น„๋™๊ธฐ ์ž‘์—…() ๋‹ค์„ฏ ๋ฒˆ์งธ ๋น„๋™๊ธฐ ์ž‘์—…() ์ฝœ๋ฐฑ ์ง€์˜ฅ (Callback Hell) ๋“ค์—ฌ์“ฐ๊ธฐ๊ฐ€ ๊ณ„์† ๊นŠ์–ด์ง€๋Š” ์ฝ”๋“œ ๊ตฌ์กฐ

์‹ค์ œ ์ฝ”๋“œ๋กœ ๋ณด๋ฉด ์ด๋Ÿฐ ๋ชจ์Šต์ด์•ผ:


// ์ฝœ๋ฐฑ ์ง€์˜ฅ์˜ ์˜ˆ์‹œ
getUserData(userId, (userData) => {
  getPostsByUser(userData.id, (posts) => {
    getCommentsForLatestPost(posts[0].id, (comments) => {
      getLikesForComments(comments, (likes) => {
        getUsersWhoLiked(likes, (users) => {
          // ์—ฌ๊ธฐ์„œ ๋ญ”๊ฐ€๋ฅผ ํ•˜๋ ค๋ฉด...
          // ๋“ค์—ฌ์“ฐ๊ธฐ๊ฐ€ ๊ณ„์† ๊นŠ์–ด์ง€๊ณ ...
          // ์ฝ”๋“œ๊ฐ€ ์ ์  ๋ณต์žกํ•ด์ง€๊ณ ...
          console.log("๋“œ๋””์–ด ์›ํ•˜๋Š” ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผ!", users);
        }, (error) => {
          console.error("์ข‹์•„์š” ๋ˆ„๋ฅธ ์‚ฌ์šฉ์ž ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ ์‹คํŒจ", error);
        });
      }, (error) => {
        console.error("์ข‹์•„์š” ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ ์‹คํŒจ", error);
      });
    }, (error) => {
      console.error("๋Œ“๊ธ€ ๊ฐ€์ ธ์˜ค๊ธฐ ์‹คํŒจ", error);
    });
  }, (error) => {
    console.error("ํฌ์ŠคํŠธ ๊ฐ€์ ธ์˜ค๊ธฐ ์‹คํŒจ", error);
  });
}, (error) => {
  console.error("์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ ์‹คํŒจ", error);
});
    

์ด๋Ÿฐ ์ฝ”๋“œ๋Š” ์ฝ๊ธฐ ์–ด๋ ต๊ณ , ์œ ์ง€๋ณด์ˆ˜ํ•˜๊ธฐ ์–ด๋ ต๊ณ , ์—๋Ÿฌ ์ฒ˜๋ฆฌ๋„ ๋ณต์žกํ•ด์ ธ. ์ด๋Ÿฐ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋“ฑ์žฅํ•œ ๊ฒƒ์ด ๋ฐ”๋กœ Promise์•ผ! ๐ŸŽ‰

3. Promise ์™„๋ฒฝ ์ดํ•ดํ•˜๊ธฐ ๐Ÿค

Promise๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ๋น„๋™๊ธฐ ์ž‘์—…์˜ ์ตœ์ข… ์™„๋ฃŒ(๋˜๋Š” ์‹คํŒจ)์™€ ๊ทธ ๊ฒฐ๊ณผ๊ฐ’์„ ๋‚˜ํƒ€๋‚ด๋Š” ๊ฐ์ฒด์•ผ. ์‰ฝ๊ฒŒ ๋งํ•˜๋ฉด, ๋ฏธ๋ž˜์— ์™„๋ฃŒ๋  ์ž‘์—…์˜ ๊ฒฐ๊ณผ๋ฅผ ์•ฝ์†(promise)ํ•˜๋Š” ๊ฐ์ฒด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋ผ!

Promise๋ฅผ ํ˜„์‹ค์— ๋น„์œ ํ•˜์ž๋ฉด ๋ ˆ์Šคํ† ๋ž‘์—์„œ ์Œ์‹์„ ์ฃผ๋ฌธํ•œ ํ›„ ๋ฐ›๋Š” '์ฃผ๋ฌธ ๋ฒˆํ˜ธํ‘œ'์™€ ๊ฐ™์•„. ๊ทธ ๋ฒˆํ˜ธํ‘œ๋Š” "์Œ์‹์ด ์ค€๋น„๋˜๋ฉด ์ด ๋ฒˆํ˜ธ๋ฅผ ํ˜ธ์ถœํ• ๊ฒŒ์š”"๋ผ๋Š” ์•ฝ์†์ด์ง€. ๋„ˆ๋Š” ๊ทธ ๋ฒˆํ˜ธํ‘œ๋ฅผ ๋“ค๊ณ  ๋‹ค๋ฅธ ์ผ์„ ํ•  ์ˆ˜ ์žˆ๊ณ , ๋ฒˆํ˜ธ๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด(Promise๊ฐ€ ์ดํ–‰๋˜๋ฉด) ์Œ์‹์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์–ด! ๐Ÿ”

3.1 Promise์˜ 3๊ฐ€์ง€ ์ƒํƒœ

Promise๋Š” ํ•ญ์ƒ ๋‹ค์Œ ์„ธ ๊ฐ€์ง€ ์ƒํƒœ ์ค‘ ํ•˜๋‚˜์•ผ:

1. Pending (๋Œ€๊ธฐ)

์ดˆ๊ธฐ ์ƒํƒœ, ์•„์ง ์ž‘์—…์ด ์™„๋ฃŒ๋˜์ง€ ์•Š์Œ

2. Fulfilled (์ดํ–‰)

์ž‘์—…์ด ์„ฑ๊ณต์ ์œผ๋กœ ์™„๋ฃŒ๋จ

3. Rejected (๊ฑฐ๋ถ€)

์ž‘์—…์ด ์‹คํŒจํ•จ

Pending Fulfilled Rejected resolve() reject() Promise ์ƒํƒœ ๋‹ค์ด์–ด๊ทธ๋žจ

3.2 Promise ์ƒ์„ฑํ•˜๊ธฐ

Promise ๊ฐ์ฒด๋Š” new Promise() ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋งŒ๋“ค์–ด. ์ด ์ƒ์„ฑ์ž๋Š” executor๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ์ธ์ž๋กœ ๋ฐ›์•„.


const myPromise = new Promise((resolve, reject) => {
  // ๋น„๋™๊ธฐ ์ž‘์—… ์ˆ˜ํ–‰
  const success = true; // ์ž‘์—… ์„ฑ๊ณต ์—ฌ๋ถ€ (์˜ˆ์‹œ)
  
  if (success) {
    // ์ž‘์—…์ด ์„ฑ๊ณตํ•˜๋ฉด resolve ํ˜ธ์ถœ
    resolve('์ž‘์—… ์„ฑ๊ณต! ์—ฌ๊ธฐ ๊ฒฐ๊ณผ๊ฐ’์ด์•ผ.');
  } else {
    // ์ž‘์—…์ด ์‹คํŒจํ•˜๋ฉด reject ํ˜ธ์ถœ
    reject(new Error('์ž‘์—… ์‹คํŒจ! ์—ฌ๊ธฐ ์—๋Ÿฌ ์ •๋ณด์•ผ.'));
  }
});
    

์‹ค์ œ ์˜ˆ์ œ๋ฅผ ํ†ตํ•ด Promise๋ฅผ ๋งŒ๋“ค์–ด๋ณผ๊นŒ?


// ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ๋ฅผ Promise๋กœ ๊ตฌํ˜„
function downloadFilePromise(url) {
  return new Promise((resolve, reject) => {
    console.log(`${url}์—์„œ ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ ์‹œ์ž‘...`);
    
    // ๋น„๋™๊ธฐ ์ž‘์—… ์‹œ๋ฎฌ๋ ˆ์ด์…˜
    setTimeout(() => {
      const random = Math.random();
      
      if (random > 0.3) { // 70% ํ™•๋ฅ ๋กœ ์„ฑ๊ณต
        const fileName = url.split('/').pop();
        console.log(`${fileName} ๋‹ค์šด๋กœ๋“œ ์™„๋ฃŒ!`);
        resolve(fileName); // ์„ฑ๊ณต ์‹œ ํŒŒ์ผ๋ช… ๋ฐ˜ํ™˜
      } else {
        reject(new Error('๋„คํŠธ์›Œํฌ ์˜ค๋ฅ˜๋กœ ๋‹ค์šด๋กœ๋“œ ์‹คํŒจ')); // ์‹คํŒจ ์‹œ ์—๋Ÿฌ ๊ฐ์ฒด ๋ฐ˜ํ™˜
      }
    }, 2000);
  });
}
    

3.3 Promise ์‚ฌ์šฉํ•˜๊ธฐ: then, catch, finally

Promise ๊ฐ์ฒด๋Š” then(), catch(), finally() ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ๊ฒฐ๊ณผ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด.


downloadFilePromise('https://example.com/photo.jpg')
  .then((fileName) => {
    console.log(`๋‹ค์šด๋กœ๋“œํ•œ ${fileName}์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.`);
    return `์ฒ˜๋ฆฌ๋œ_${fileName}`; // ๋‹ค์Œ then์œผ๋กœ ๊ฐ’์„ ์ „๋‹ฌ
  })
  .then((processedFile) => {
    console.log(`${processedFile}์„ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.`);
    return `์ €์žฅ๋œ_${processedFile}`; // ์ฒด์ด๋‹ ๊ณ„์† ๊ฐ€๋Šฅ
  })
  .catch((error) => {
    console.error(`์˜ค๋ฅ˜ ๋ฐœ์ƒ: ${error.message}`);
  })
  .finally(() => {
    console.log('๋‹ค์šด๋กœ๋“œ ์ž‘์—… ์ข…๋ฃŒ (์„ฑ๊ณต์ด๋“  ์‹คํŒจ๋“ )');
  });

console.log('๋‹ค์šด๋กœ๋“œ ๋ช…๋ น ํ›„ ์ฆ‰์‹œ ์‹คํ–‰๋˜๋Š” ์ฝ”๋“œ');
    

์œ„ ์ฝ”๋“œ์˜ ์‹คํ–‰ ์ˆœ์„œ๋Š”:

  1. "https://example.com/photo.jpg์—์„œ ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ ์‹œ์ž‘..." ์ถœ๋ ฅ
  2. "๋‹ค์šด๋กœ๋“œ ๋ช…๋ น ํ›„ ์ฆ‰์‹œ ์‹คํ–‰๋˜๋Š” ์ฝ”๋“œ" ์ถœ๋ ฅ
  3. 2์ดˆ ํ›„, ์„ฑ๊ณต ์‹œ:
  4. "photo.jpg ๋‹ค์šด๋กœ๋“œ ์™„๋ฃŒ!" ์ถœ๋ ฅ
  5. "๋‹ค์šด๋กœ๋“œํ•œ photo.jpg์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค." ์ถœ๋ ฅ
  6. "์ฒ˜๋ฆฌ๋œ_photo.jpg์„ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค." ์ถœ๋ ฅ
  7. "๋‹ค์šด๋กœ๋“œ ์ž‘์—… ์ข…๋ฃŒ (์„ฑ๊ณต์ด๋“  ์‹คํŒจ๋“ )" ์ถœ๋ ฅ

3.4 Promise ์ฒด์ด๋‹

Promise ์ฒด์ด๋‹์€ ์—ฌ๋Ÿฌ ๋น„๋™๊ธฐ ์ž‘์—…์„ ์ˆœ์ฐจ์ ์œผ๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ์ด์•ผ. ์ฝœ๋ฐฑ ์ง€์˜ฅ์„ ํ‰ํ‰ํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ์ง€! ๐Ÿ˜Ž


// ์ฝœ๋ฐฑ ์ง€์˜ฅ์„ Promise ์ฒด์ด๋‹์œผ๋กœ ๋ณ€ํ™˜
getUserDataPromise(userId)
  .then(userData => {
    return getPostsByUserPromise(userData.id);
  })
  .then(posts => {
    return getCommentsForLatestPostPromise(posts[0].id);
  })
  .then(comments => {
    return getLikesForCommentsPromise(comments);
  })
  .then(likes => {
    return getUsersWhoLikedPromise(likes);
  })
  .then(users => {
    console.log("๋“œ๋””์–ด ์›ํ•˜๋Š” ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผ!", users);
  })
  .catch(error => {
    console.error("์–ด๋””์„ ๊ฐ€ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:", error);
  });
    

๋” ๊ฐ„๊ฒฐํ•˜๊ฒŒ ํ™”์‚ดํ‘œ ํ•จ์ˆ˜์˜ ์•”์‹œ์  ๋ฐ˜ํ™˜์„ ์‚ฌ์šฉํ•˜๋ฉด:


getUserDataPromise(userId)
  .then(userData => getPostsByUserPromise(userData.id))
  .then(posts => getCommentsForLatestPostPromise(posts[0].id))
  .then(comments => getLikesForCommentsPromise(comments))
  .then(likes => getUsersWhoLikedPromise(likes))
  .then(users => console.log("๋“œ๋””์–ด ์›ํ•˜๋Š” ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผ!", users))
  .catch(error => console.error("์–ด๋””์„ ๊ฐ€ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:", error));
    

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ฝ”๋“œ๊ฐ€ ํ›จ์”ฌ ๋” ์ฝ๊ธฐ ์‰ฝ๊ณ  ์œ ์ง€๋ณด์ˆ˜ํ•˜๊ธฐ ์‰ฌ์›Œ์ ธ! ๋“ค์—ฌ์“ฐ๊ธฐ ๋ ˆ๋ฒจ๋„ ์ผ์ •ํ•˜๊ฒŒ ์œ ์ง€๋˜๊ณ , ์—๋Ÿฌ ์ฒ˜๋ฆฌ๋„ ํ•œ ๊ณณ์—์„œ ํ•  ์ˆ˜ ์žˆ์–ด.

3.5 Promise.all, Promise.race, Promise.allSettled

์—ฌ๋Ÿฌ Promise๋ฅผ ๋™์‹œ์— ์ฒ˜๋ฆฌํ•ด์•ผ ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๋ฉ”์„œ๋“œ๋“ค์ด์•ผ:

Promise.all()

์—ฌ๋Ÿฌ Promise๋ฅผ ๋ณ‘๋ ฌ๋กœ ์‹คํ–‰ํ•˜๊ณ  ๋ชจ๋“  Promise๊ฐ€ ์„ฑ๊ณตํ–ˆ์„ ๋•Œ ๊ฒฐ๊ณผ ๋ฐฐ์—ด์„ ๋ฐ˜ํ™˜ํ•ด. ํ•˜๋‚˜๋ผ๋„ ์‹คํŒจํ•˜๋ฉด ์ „์ฒด๊ฐ€ ์‹คํŒจ๋กœ ๊ฐ„์ฃผ๋ผ.

Promise.race()

๊ฐ€์žฅ ๋จผ์ € ์™„๋ฃŒ๋˜๋Š” Promise์˜ ๊ฒฐ๊ณผ(์„ฑ๊ณต ๋˜๋Š” ์‹คํŒจ)๋ฅผ ๋ฐ˜ํ™˜ํ•ด.

Promise.allSettled()

๋ชจ๋“  Promise๊ฐ€ ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๊ณ , ๊ฐ Promise์˜ ์ƒํƒœ์™€ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ฒด ๋ฐฐ์—ด๋กœ ๋ฐ˜ํ™˜ํ•ด. (ES2020์—์„œ ์ถ”๊ฐ€)


// ์—ฌ๋Ÿฌ ํŒŒ์ผ์„ ๋™์‹œ์— ๋‹ค์šด๋กœ๋“œํ•˜๋Š” ์˜ˆ์ œ
const fileUrls = [
  'https://example.com/file1.jpg',
  'https://example.com/file2.jpg',
  'https://example.com/file3.jpg'
];

// Promise.all ์˜ˆ์ œ
Promise.all(fileUrls.map(url => downloadFilePromise(url)))
  .then(fileNames => {
    console.log('๋ชจ๋“  ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ ์™„๋ฃŒ:', fileNames);
  })
  .catch(error => {
    console.error('ํ•˜๋‚˜ ์ด์ƒ์˜ ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ ์‹คํŒจ:', error);
  });

// Promise.race ์˜ˆ์ œ
Promise.race(fileUrls.map(url => downloadFilePromise(url)))
  .then(fileName => {
    console.log('๊ฐ€์žฅ ๋จผ์ € ๋‹ค์šด๋กœ๋“œ๋œ ํŒŒ์ผ:', fileName);
  })
  .catch(error => {
    console.error('๊ฐ€์žฅ ๋จผ์ € ์‹คํŒจํ•œ ๋‹ค์šด๋กœ๋“œ:', error);
  });

// Promise.allSettled ์˜ˆ์ œ
Promise.allSettled(fileUrls.map(url => downloadFilePromise(url)))
  .then(results => {
    results.forEach((result, index) => {
      if (result.status === 'fulfilled') {
        console.log(`${fileUrls[index]} ๋‹ค์šด๋กœ๋“œ ์„ฑ๊ณต:`, result.value);
      } else {
        console.log(`${fileUrls[index]} ๋‹ค์šด๋กœ๋“œ ์‹คํŒจ:`, result.reason);
      }
    });
  });
    

์ด๋Ÿฐ ๋ฉ”์„œ๋“œ๋“ค์€ ์—ฌ๋Ÿฌ ๋น„๋™๊ธฐ ์ž‘์—…์„ ํšจ์œจ์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค˜. ํŠนํžˆ API ํ˜ธ์ถœ์ด๋‚˜ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ๊ฐ™์€ ์ž‘์—…์—์„œ ๋งค์šฐ ์œ ์šฉํ•ด! ๐Ÿš€

4. async/await ๋งˆ์Šคํ„ฐํ•˜๊ธฐ โณ

Promise๋Š” ์ฝœ๋ฐฑ ์ง€์˜ฅ์„ ํ•ด๊ฒฐํ•ด์คฌ์ง€๋งŒ, ์—ฌ์ „ํžˆ .then() ์ฒด์ธ์ด ๊ธธ์–ด์ง€๋ฉด ์ฝ”๋“œ๊ฐ€ ๋ณต์žกํ•ด์งˆ ์ˆ˜ ์žˆ์–ด. ๊ทธ๋ž˜์„œ ES2017์—์„œ๋Š” async/await๋ผ๋Š” ๋” ์ง๊ด€์ ์ธ ๋ฌธ๋ฒ•์ด ๋„์ž…๋์–ด!

async/await๋Š” ๋น„๋™๊ธฐ ์ฝ”๋“œ๋ฅผ ๋งˆ์น˜ ๋™๊ธฐ ์ฝ”๋“œ์ฒ˜๋Ÿผ ๋ณด์ด๊ฒŒ ํ•ด์ค˜. ๋งˆ์น˜ ์š”๋ฆฌ ๋ ˆ์‹œํ”ผ๋ฅผ ๋”ฐ๋ผ๊ฐ€๋“ฏ์ด "์ด ์ž‘์—…์ด ๋๋‚˜๋ฉด ๋‹ค์Œ ์ž‘์—…"์ด๋ผ๋Š” ์ˆœ์„œ๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์ง€! ๐Ÿณ

4.1 async ํ•จ์ˆ˜ ๊ธฐ๋ณธ

async ํ‚ค์›Œ๋“œ๋Š” ํ•จ์ˆ˜๋ฅผ ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋กœ ์„ ์–ธํ•ด. async ํ•จ์ˆ˜๋Š” ํ•ญ์ƒ Promise๋ฅผ ๋ฐ˜ํ™˜ํ•ด!


// ๊ธฐ๋ณธ async ํ•จ์ˆ˜
async function greet() {
  return "์•ˆ๋…•ํ•˜์„ธ์š”!";
}

// ์œ„ ํ•จ์ˆ˜๋Š” ๋‹ค์Œ๊ณผ ๋™์ผํ•ด:
// function greet() {
//   return Promise.resolve("์•ˆ๋…•ํ•˜์„ธ์š”!");
// }

greet().then(message => console.log(message)); // "์•ˆ๋…•ํ•˜์„ธ์š”!" ์ถœ๋ ฅ
    

4.2 await ํ‚ค์›Œ๋“œ ์‚ฌ์šฉํ•˜๊ธฐ

await ํ‚ค์›Œ๋“œ๋Š” Promise๊ฐ€ ์ฒ˜๋ฆฌ๋  ๋•Œ๊นŒ์ง€ ํ•จ์ˆ˜ ์‹คํ–‰์„ ์ผ์‹œ ์ค‘์ง€์‹œ์ผœ. ๊ทธ๋ฆฌ๊ณ  Promise์˜ ๊ฒฐ๊ณผ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ด. await๋Š” async ํ•จ์ˆ˜ ๋‚ด์—์„œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด!


async function downloadAndProcessFile(url) {
  try {
    console.log(`${url} ๋‹ค์šด๋กœ๋“œ ์‹œ์ž‘...`);
    
    // await๋Š” Promise๊ฐ€ ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ ค
    const fileName = await downloadFilePromise(url);
    console.log(`${fileName} ๋‹ค์šด๋กœ๋“œ ์™„๋ฃŒ!`);
    
    // ์ฒซ ๋ฒˆ์งธ ์ž‘์—…์ด ์™„๋ฃŒ๋œ ํ›„์— ๋‘ ๋ฒˆ์งธ ์ž‘์—… ์‹œ์ž‘
    const processedFile = `์ฒ˜๋ฆฌ๋œ_${fileName}`;
    console.log(`${fileName}์„ ์ฒ˜๋ฆฌํ•ด์„œ ${processedFile} ์ƒ์„ฑ`);
    
    // ๋‘ ๋ฒˆ์งธ ์ž‘์—…์ด ์™„๋ฃŒ๋œ ํ›„์— ์„ธ ๋ฒˆ์งธ ์ž‘์—… ์‹œ์ž‘
    const savedFile = `์ €์žฅ๋œ_${processedFile}`;
    console.log(`${processedFile}์„ ์ €์žฅํ•ด์„œ ${savedFile} ์ƒ์„ฑ`);
    
    return savedFile;
  } catch (error) {
    // try/catch๋กœ ์—๋Ÿฌ ์ฒ˜๋ฆฌ
    console.error(`์˜ค๋ฅ˜ ๋ฐœ์ƒ: ${error.message}`);
    throw error; // ํ•„์š”ํ•˜๋‹ค๋ฉด ์—๋Ÿฌ๋ฅผ ๋‹ค์‹œ ๋˜์งˆ ์ˆ˜ ์žˆ์–ด
  } finally {
    console.log('๋‹ค์šด๋กœ๋“œ ์ž‘์—… ์ข…๋ฃŒ (์„ฑ๊ณต์ด๋“  ์‹คํŒจ๋“ )');
  }
}

// async ํ•จ์ˆ˜ ํ˜ธ์ถœ
downloadAndProcessFile('https://example.com/photo.jpg')
  .then(result => console.log('์ตœ์ข… ๊ฒฐ๊ณผ:', result))
  .catch(error => console.error('์ตœ์ข… ์—๋Ÿฌ ์ฒ˜๋ฆฌ:', error));

console.log('๋‹ค์šด๋กœ๋“œ ๋ช…๋ น ํ›„ ์ฆ‰์‹œ ์‹คํ–‰๋˜๋Š” ์ฝ”๋“œ');
    

์œ„ ์ฝ”๋“œ์˜ ์‹คํ–‰ ์ˆœ์„œ๋Š”:

  1. "https://example.com/photo.jpg ๋‹ค์šด๋กœ๋“œ ์‹œ์ž‘..." ์ถœ๋ ฅ
  2. "๋‹ค์šด๋กœ๋“œ ๋ช…๋ น ํ›„ ์ฆ‰์‹œ ์‹คํ–‰๋˜๋Š” ์ฝ”๋“œ" ์ถœ๋ ฅ
  3. 2์ดˆ ํ›„, ์„ฑ๊ณต ์‹œ:
  4. "photo.jpg ๋‹ค์šด๋กœ๋“œ ์™„๋ฃŒ!" ์ถœ๋ ฅ
  5. "photo.jpg์„ ์ฒ˜๋ฆฌํ•ด์„œ ์ฒ˜๋ฆฌ๋œ_photo.jpg ์ƒ์„ฑ" ์ถœ๋ ฅ
  6. "์ฒ˜๋ฆฌ๋œ_photo.jpg์„ ์ €์žฅํ•ด์„œ ์ €์žฅ๋œ_์ฒ˜๋ฆฌ๋œ_photo.jpg ์ƒ์„ฑ" ์ถœ๋ ฅ
  7. "๋‹ค์šด๋กœ๋“œ ์ž‘์—… ์ข…๋ฃŒ (์„ฑ๊ณต์ด๋“  ์‹คํŒจ๋“ )" ์ถœ๋ ฅ
  8. "์ตœ์ข… ๊ฒฐ๊ณผ: ์ €์žฅ๋œ_์ฒ˜๋ฆฌ๋œ_photo.jpg" ์ถœ๋ ฅ

4.3 Promise ์ฒด์ด๋‹๊ณผ async/await ๋น„๊ต

์ด์ „์— ๋ดค๋˜ Promise ์ฒด์ด๋‹ ์˜ˆ์ œ๋ฅผ async/await๋กœ ๋ณ€ํ™˜ํ•ด๋ณด์ž:

Promise ์ฒด์ด๋‹:


getUserDataPromise(userId)
  .then(userData => getPostsByUserPromise(userData.id))
  .then(posts => getCommentsForLatestPostPromise(posts[0].id))
  .then(comments => getLikesForCommentsPromise(comments))
  .then(likes => getUsersWhoLikedPromise(likes))
  .then(users => console.log("๋“œ๋””์–ด ์›ํ•˜๋Š” ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผ!", users))
  .catch(error => console.error("์–ด๋””์„ ๊ฐ€ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:", error));
        

async/await:


async function getUsersWhoLikedLatestPost(userId) {
  try {
    const userData = await getUserDataPromise(userId);
    const posts = await getPostsByUserPromise(userData.id);
    const comments = await getCommentsForLatestPostPromise(posts[0].id);
    const likes = await getLikesForCommentsPromise(comments);
    const users = await getUsersWhoLikedPromise(likes);
    
    console.log("๋“œ๋””์–ด ์›ํ•˜๋Š” ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผ!", users);
    return users;
  } catch (error) {
    console.error("์–ด๋””์„ ๊ฐ€ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:", error);
    throw error;
  }
}

// ํ•จ์ˆ˜ ํ˜ธ์ถœ
getUsersWhoLikedLatestPost(123);
        

async/await๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ฝ”๋“œ๊ฐ€ ๋” ์ง๊ด€์ ์ด๊ณ  ์ฝ๊ธฐ ์‰ฌ์›Œ์ ธ. ๋งˆ์น˜ ๋™๊ธฐ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์ˆœ์ฐจ์ ์œผ๋กœ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์–ด์„œ ๋กœ์ง์„ ์ดํ•ดํ•˜๊ธฐ ์‰ฝ์ง€!

4.4 ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ์™€ async/await

์ฃผ์˜ํ•  ์ ์€ await๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ธฐ๋ณธ์ ์œผ๋กœ ์ž‘์—…์ด ์ˆœ์ฐจ์ ์œผ๋กœ ์‹คํ–‰๋œ๋‹ค๋Š” ๊ฑฐ์•ผ. ๋งŒ์•ฝ ์—ฌ๋Ÿฌ ๋น„๋™๊ธฐ ์ž‘์—…์„ ๋ณ‘๋ ฌ๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด Promise.all๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ฉด ๋ผ!


// ์ˆœ์ฐจ ์ฒ˜๋ฆฌ (๊ฐ ๋‹ค์šด๋กœ๋“œ๊ฐ€ ์™„๋ฃŒ๋œ ํ›„ ๋‹ค์Œ ๋‹ค์šด๋กœ๋“œ ์‹œ์ž‘)
async function downloadFilesSequentially(urls) {
  const fileNames = [];
  
  for (const url of urls) {
    const fileName = await downloadFilePromise(url); // ๊ฐ ๋‹ค์šด๋กœ๋“œ๋ฅผ ๊ธฐ๋‹ค๋ฆผ
    fileNames.push(fileName);
  }
  
  return fileNames;
}

// ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ (๋ชจ๋“  ๋‹ค์šด๋กœ๋“œ๋ฅผ ๋™์‹œ์— ์‹œ์ž‘)
async function downloadFilesParallel(urls) {
  // Promise.all๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ฉด ๋ชจ๋“  Promise๋ฅผ ๋™์‹œ์— ์‹คํ–‰
  const fileNames = await Promise.all(
    urls.map(url => downloadFilePromise(url))
  );
  
  return fileNames;
}

// ์‚ฌ์šฉ ์˜ˆ
const urls = [
  'https://example.com/file1.jpg',
  'https://example.com/file2.jpg',
  'https://example.com/file3.jpg'
];

// ์ˆœ์ฐจ ์ฒ˜๋ฆฌ (์•ฝ 6์ดˆ ์†Œ์š”)
downloadFilesSequentially(urls)
  .then(files => console.log('์ˆœ์ฐจ ๋‹ค์šด๋กœ๋“œ ์™„๋ฃŒ:', files));

// ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ (์•ฝ 2์ดˆ ์†Œ์š”)
downloadFilesParallel(urls)
  .then(files => console.log('๋ณ‘๋ ฌ ๋‹ค์šด๋กœ๋“œ ์™„๋ฃŒ:', files));
    

์„ฑ๋Šฅ์ด ์ค‘์š”ํ•œ ๊ฒฝ์šฐ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ๋ฅผ ๊ณ ๋ คํ•ด๋ด์•ผ ํ•ด. ํ•˜์ง€๋งŒ ์ž‘์—… ๊ฐ„์— ์˜์กด์„ฑ์ด ์žˆ๋‹ค๋ฉด ์ˆœ์ฐจ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•  ์ˆ˜๋„ ์žˆ์–ด!

4.5 async/await์˜ ์—๋Ÿฌ ์ฒ˜๋ฆฌ

async/await์˜ ํฐ ์žฅ์  ์ค‘ ํ•˜๋‚˜๋Š” try/catch ๊ตฌ๋ฌธ์œผ๋กœ ์—๋Ÿฌ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฑฐ์•ผ. ์ด๋Š” ๋™๊ธฐ ์ฝ”๋“œ์™€ ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ ์—๋Ÿฌ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค˜!


async function fetchUserData(userId) {
  try {
    const response = await fetch(`https://api.example.com/users/${userId}`);
    
    if (!response.ok) {
      throw new Error(`HTTP ์—๋Ÿฌ! ์ƒํƒœ: ${response.status}`);
    }
    
    const userData = await response.json();
    return userData;
  } catch (error) {
    console.error(`์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ ์‹คํŒจ: ${error.message}`);
    
    // ์—๋Ÿฌ ์ข…๋ฅ˜์— ๋”ฐ๋ผ ๋‹ค๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜๋„ ์žˆ์–ด
    if (error.message.includes('404')) {
      return { error: '์‚ฌ์šฉ์ž๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.' };
    }
    
    return { error: '์„œ๋ฒ„ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.' };
  }
}
    

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๋กœ์ง์ด ๋” ๋ช…ํ™•ํ•ด์ง€๊ณ , ํŠน์ • ์—๋Ÿฌ ์œ ํ˜•์— ๋”ฐ๋ผ ๋‹ค๋ฅด๊ฒŒ ๋Œ€์‘ํ•  ์ˆ˜๋„ ์žˆ์–ด!

5. ์‹ค์ „ ์˜ˆ์ œ๋กœ ๋ฐฐ์šฐ๋Š” ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ๐Ÿ› ๏ธ

์ด์ œ ์‹ค์ œ ์›น ๊ฐœ๋ฐœ์—์„œ ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ์˜ˆ์ œ๋“ค์„ ์‚ดํŽด๋ณผ๊ฒŒ. ์ด๋ก ๋ณด๋‹ค ์‹ค์ „์ด ๋” ์žฌ๋ฐŒ์ž–์•„! ๐Ÿ˜„

5.1 API ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ

์›น ๊ฐœ๋ฐœ์—์„œ ๊ฐ€์žฅ ํ”ํ•œ ๋น„๋™๊ธฐ ์ž‘์—…์€ API์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์ด์•ผ. fetch API์™€ async/await๋ฅผ ์‚ฌ์šฉํ•ด๋ณด์ž:


// ์˜ํ™” ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ํ•จ์ˆ˜
async function fetchMovies(searchTerm) {
  try {
    const response = await fetch(`https://api.example.com/movies?q=${searchTerm}`);
    
    if (!response.ok) {
      throw new Error(`API ์˜ค๋ฅ˜! ์ƒํƒœ: ${response.status}`);
    }
    
    const data = await response.json();
    return data.movies;
  } catch (error) {
    console.error('์˜ํ™” ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ ์‹คํŒจ:', error);
    return [];
  }
}

// ์˜ํ™” ๋ชฉ๋ก์„ ํ™”๋ฉด์— ํ‘œ์‹œํ•˜๋Š” ํ•จ์ˆ˜
async function displayMovies(searchTerm) {
  const movies = await fetchMovies(searchTerm);
  
  if (movies.length === 0) {
    console.log('๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.');
    return;
  }
  
  console.log(`'${searchTerm}' ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ:`);
  movies.forEach(movie => {
    console.log(`- ${movie.title} (${movie.year}): ${movie.rating}/10`);
  });
}

// ์‚ฌ์šฉ ์˜ˆ
displayMovies('์ธํ„ฐ์Šคํ…”๋ผ');
    

5.2 ์ด๋ฏธ์ง€ ํ”„๋ฆฌ๋กœ๋”ฉ

์›น์‚ฌ์ดํŠธ์˜ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ค๊ธฐ ์œ„ํ•ด ์ด๋ฏธ์ง€๋ฅผ ๋ฏธ๋ฆฌ ๋กœ๋“œํ•˜๋Š” ์˜ˆ์ œ๋ฅผ ์‚ดํŽด๋ณด์ž:


// ์ด๋ฏธ์ง€ ํ”„๋ฆฌ๋กœ๋”ฉ ํ•จ์ˆ˜
function preloadImage(url) {
  return new Promise((resolve, reject) => {
    const img = new Image();
    
    img.onload = () => {
      console.log(`์ด๋ฏธ์ง€ ๋กœ๋“œ ์™„๋ฃŒ: ${url}`);
      resolve(img);
    };
    
    img.onerror = () => {
      reject(new Error(`์ด๋ฏธ์ง€ ๋กœ๋“œ ์‹คํŒจ: ${url}`));
    };
    
    img.src = url;
  });
}

// ์—ฌ๋Ÿฌ ์ด๋ฏธ์ง€ ํ”„๋ฆฌ๋กœ๋”ฉ
async function preloadGalleryImages(urls) {
  try {
    console.log('๊ฐค๋Ÿฌ๋ฆฌ ์ด๋ฏธ์ง€ ํ”„๋ฆฌ๋กœ๋”ฉ ์‹œ์ž‘...');
    const images = await Promise.all(urls.map(url => preloadImage(url)));
    console.log(`${images.length}๊ฐœ ์ด๋ฏธ์ง€ ํ”„๋ฆฌ๋กœ๋”ฉ ์™„๋ฃŒ!`);
    return images;
  } catch (error) {
    console.error('์ด๋ฏธ์ง€ ํ”„๋ฆฌ๋กœ๋”ฉ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:', error);
    throw error;
  }
}

// ์‚ฌ์šฉ ์˜ˆ
const imageUrls = [
  'https://example.com/gallery/image1.jpg',
  'https://example.com/gallery/image2.jpg',
  'https://example.com/gallery/image3.jpg'
];

preloadGalleryImages(imageUrls)
  .then(images => {
    console.log('์ด์ œ ๊ฐค๋Ÿฌ๋ฆฌ๋ฅผ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!');
    // ์—ฌ๊ธฐ์„œ ์ด๋ฏธ์ง€๋ฅผ DOM์— ์ถ”๊ฐ€ํ•˜๋Š” ๋“ฑ์˜ ์ž‘์—… ์ˆ˜ํ–‰
  })
  .catch(error => {
    console.error('๊ฐค๋Ÿฌ๋ฆฌ ๋กœ๋”ฉ ์‹คํŒจ:', error);
    // ์—๋Ÿฌ ์ฒ˜๋ฆฌ (๋Œ€์ฒด ์ด๋ฏธ์ง€ ํ‘œ์‹œ ๋“ฑ)
  });
    

5.3 ํƒ€์ž„์•„์›ƒ ์„ค์ •ํ•˜๊ธฐ

๋„คํŠธ์›Œํฌ ์š”์ฒญ์ด ๋„ˆ๋ฌด ์˜ค๋ž˜ ๊ฑธ๋ฆด ๊ฒฝ์šฐ๋ฅผ ๋Œ€๋น„ํ•ด ํƒ€์ž„์•„์›ƒ์„ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์•„:


// Promise์— ํƒ€์ž„์•„์›ƒ ์ถ”๊ฐ€ํ•˜๋Š” ํ•จ์ˆ˜
function withTimeout(promise, timeoutMs) {
  // ํƒ€์ž„์•„์›ƒ์šฉ Promise ์ƒ์„ฑ
  const timeoutPromise = new Promise((_, reject) => {
    setTimeout(() => {
      reject(new Error(`์ž‘์—… ์‹œ๊ฐ„ ์ดˆ๊ณผ! (${timeoutMs}ms)`));
    }, timeoutMs);
  });
  
  // ๋‘˜ ์ค‘ ๋จผ์ € ์™„๋ฃŒ๋˜๋Š” Promise ๋ฐ˜ํ™˜ (race)
  return Promise.race([promise, timeoutPromise]);
}

// ์‚ฌ์šฉ ์˜ˆ: API ์š”์ฒญ์— 5์ดˆ ํƒ€์ž„์•„์›ƒ ์„ค์ •
async function fetchUserWithTimeout(userId) {
  try {
    const userPromise = fetch(`https://api.example.com/users/${userId}`)
      .then(response => response.json());
    
    // 5์ดˆ ํƒ€์ž„์•„์›ƒ ์„ค์ •
    const userData = await withTimeout(userPromise, 5000);
    console.log('์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ:', userData);
    return userData;
  } catch (error) {
    if (error.message.includes('์‹œ๊ฐ„ ์ดˆ๊ณผ')) {
      console.error('์„œ๋ฒ„ ์‘๋‹ต์ด ๋„ˆ๋ฌด ๋Š๋ฆฝ๋‹ˆ๋‹ค!');
    } else {
      console.error('๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ ์‹คํŒจ:', error);
    }
    throw error;
  }
}

// ์‚ฌ์šฉ
fetchUserWithTimeout(123)
  .catch(error => {
    // ์—๋Ÿฌ ์ฒ˜๋ฆฌ
    console.log('์‚ฌ์šฉ์ž์—๊ฒŒ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ:', error.message);
  });
    

5.4 ์žฌ์‹œ๋„ ๋ฉ”์ปค๋‹ˆ์ฆ˜ ๊ตฌํ˜„ํ•˜๊ธฐ

๋„คํŠธ์›Œํฌ ์š”์ฒญ์ด ์‹คํŒจํ–ˆ์„ ๋•Œ ์ž๋™์œผ๋กœ ์žฌ์‹œ๋„ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•ด๋ณด์ž:


// ์žฌ์‹œ๋„ ๊ธฐ๋Šฅ์ด ์žˆ๋Š” ๋น„๋™๊ธฐ ํ•จ์ˆ˜
async function fetchWithRetry(url, options = {}, maxRetries = 3, delayMs = 1000) {
  let lastError;
  
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      console.log(`์‹œ๋„ ${attempt}/${maxRetries}: ${url} ์š”์ฒญ ์ค‘...`);
      const response = await fetch(url, options);
      
      if (!response.ok) {
        throw new Error(`HTTP ์—๋Ÿฌ! ์ƒํƒœ: ${response.status}`);
      }
      
      return await response.json(); // ์„ฑ๊ณต ์‹œ ๋ฐ์ดํ„ฐ ๋ฐ˜ํ™˜
    } catch (error) {
      console.warn(`์‹œ๋„ ${attempt} ์‹คํŒจ:`, error.message);
      lastError = error;
      
      if (attempt < maxRetries) {
        // ์žฌ์‹œ๋„ ์ „ ์ง€์—ฐ ์‹œ๊ฐ„ (์„ ํ˜• ๋˜๋Š” ์ง€์ˆ˜ ๋ฐฑ์˜คํ”„ ์ ์šฉ ๊ฐ€๋Šฅ)
        const delay = delayMs * attempt; // ์„ ํ˜• ๋ฐฑ์˜คํ”„
        console.log(`${delay}ms ํ›„ ์žฌ์‹œ๋„...`);
        await new Promise(resolve => setTimeout(resolve, delay));
      }
    }
  }
  
  // ๋ชจ๋“  ์‹œ๋„ ์‹คํŒจ ์‹œ
  throw new Error(`${maxRetries}๋ฒˆ ์‹œ๋„ ํ›„ ์‹คํŒจ: ${lastError.message}`);
}

// ์‚ฌ์šฉ ์˜ˆ
async function getWeatherData(city) {
  try {
    const data = await fetchWithRetry(
      `https://api.weather.example.com/forecast?city=${city}`,
      {}, // ๊ธฐ๋ณธ ์˜ต์…˜
      3,  // ์ตœ๋Œ€ 3๋ฒˆ ์‹œ๋„
      500 // 500ms๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๋Š” ๋ฐฑ์˜คํ”„
    );
    
    console.log(`${city}์˜ ๋‚ ์”จ:`, data.forecast);
    return data;
  } catch (error) {
    console.error('๋‚ ์”จ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค:', error);
    return { error: '๋‚ ์”จ ์ •๋ณด๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋‚˜์ค‘์— ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.' };
  }
}

// ์‚ฌ์šฉ
getWeatherData('์„œ์šธ');
    

5.5 ๋น„๋™๊ธฐ ๋ฐ์ดํ„ฐ ์บ์‹ฑ

์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” API ๋ฐ์ดํ„ฐ๋ฅผ ์บ์‹ฑํ•˜์—ฌ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ค๋Š” ์˜ˆ์ œ:


// ๊ฐ„๋‹จํ•œ ๋ฉ”๋ชจ๋ฆฌ ์บ์‹œ ๊ตฌํ˜„
class AsyncCache {
  constructor(ttlMs = 60000) { // ๊ธฐ๋ณธ TTL: 1๋ถ„
    this.cache = new Map();
    this.ttlMs = ttlMs;
  }
  
  async getOrFetch(key, fetchFn) {
    // ์บ์‹œ์— ์œ ํšจํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธ
    if (this.cache.has(key)) {
      const cacheEntry = this.cache.get(key);
      
      // ์บ์‹œ๊ฐ€ ์•„์ง ์œ ํšจํ•œ์ง€ ํ™•์ธ
      if (Date.now() < cacheEntry.expiresAt) {
        console.log(`์บ์‹œ ํžˆํŠธ: ${key}`);
        return cacheEntry.data;
      } else {
        console.log(`์บ์‹œ ๋งŒ๋ฃŒ: ${key}`);
        this.cache.delete(key);
      }
    }
    
    // ์บ์‹œ์— ์—†์œผ๋ฉด ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ
    console.log(`์บ์‹œ ๋ฏธ์Šค: ${key}, ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๋Š” ์ค‘...`);
    try {
      const data = await fetchFn();
      
      // ๊ฒฐ๊ณผ๋ฅผ ์บ์‹œ์— ์ €์žฅ
      this.cache.set(key, {
        data,
        expiresAt: Date.now() + this.ttlMs
      });
      
      return data;
    } catch (error) {
      console.error(`๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ ์‹คํŒจ: ${key}`, error);
      throw error;
    }
  }
  
  invalidate(key) {
    console.log(`์บ์‹œ ๋ฌดํšจํ™”: ${key}`);
    return this.cache.delete(key);
  }
  
  clear() {
    console.log('์บ์‹œ ์ „์ฒด ์‚ญ์ œ');
    this.cache.clear();
  }
}

// ์‚ฌ์šฉ ์˜ˆ
const apiCache = new AsyncCache(5 * 60 * 1000); // 5๋ถ„ TTL

async function getUserProfile(userId) {
  return apiCache.getOrFetch(
    `user_${userId}`,
    async () => {
      const response = await fetch(`https://api.example.com/users/${userId}`);
      if (!response.ok) throw new Error(`API ์˜ค๋ฅ˜: ${response.status}`);
      return response.json();
    }
  );
}

// ์ฒซ ๋ฒˆ์งธ ํ˜ธ์ถœ: API์—์„œ ๊ฐ€์ ธ์˜ด
getUserProfile(123).then(profile => console.log('ํ”„๋กœํ•„:', profile));

// ์ž ์‹œ ํ›„ ๋‹ค์‹œ ํ˜ธ์ถœ: ์บ์‹œ์—์„œ ๊ฐ€์ ธ์˜ด
setTimeout(() => {
  getUserProfile(123).then(profile => console.log('ํ”„๋กœํ•„ (์บ์‹œ๋จ):', profile));
}, 2000);

// ์‚ฌ์šฉ์ž ์ •๋ณด๊ฐ€ ์—…๋ฐ์ดํŠธ๋˜์—ˆ์„ ๋•Œ ์บ์‹œ ๋ฌดํšจํ™”
function updateUserProfile(userId, newData) {
  // API ํ˜ธ์ถœ๋กœ ํ”„๋กœํ•„ ์—…๋ฐ์ดํŠธ
  fetch(`https://api.example.com/users/${userId}`, {
    method: 'PUT',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(newData)
  })
  .then(response => {
    if (response.ok) {
      // ์—…๋ฐ์ดํŠธ ์„ฑ๊ณต ์‹œ ์บ์‹œ ๋ฌดํšจํ™”
      apiCache.invalidate(`user_${userId}`);
    }
    return response.json();
  })
  .then(data => console.log('ํ”„๋กœํ•„ ์—…๋ฐ์ดํŠธ๋จ:', data))
  .catch(error => console.error('ํ”„๋กœํ•„ ์—…๋ฐ์ดํŠธ ์‹คํŒจ:', error));
}
    

์ด๋Ÿฐ ์‹ค์ „ ์˜ˆ์ œ๋“ค์€ ์žฌ๋Šฅ๋„ท์—์„œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์žฌ๋Šฅ์„ ๊ณต์œ ํ•˜๊ฑฐ๋‚˜ ๊ตฌ๋งคํ•  ๋•Œ ์ •๋ง ์œ ์šฉํ•œ ์ง€์‹์ด ๋  ์ˆ˜ ์žˆ์–ด! ์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ํŒจํ„ด๋“ค์ด๊ฑฐ๋“ . ๐Ÿ˜Š

7. ์„ฑ๋Šฅ ์ตœ์ ํ™” ํŒ โšก

๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ๋งˆ์Šคํ„ฐํ–ˆ๋‹ค๋ฉด, ์ด์ œ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์ž! 2025๋…„ ํ˜„์žฌ, ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์„ฑ๋Šฅ์€ ๊ทธ ์–ด๋Š ๋•Œ๋ณด๋‹ค ์ค‘์š”ํ•ด์กŒ์–ด.

7.1 ๋น„๋™๊ธฐ ์ž‘์—… ๋ณ‘๋ ฌํ™”

๋…๋ฆฝ์ ์ธ ๋น„๋™๊ธฐ ์ž‘์—…์€ ๊ฐ€๋Šฅํ•œ ํ•œ ๋ณ‘๋ ฌ๋กœ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์•„:


// ์ˆœ์ฐจ ์‹คํ–‰ (๋Š๋ฆผ)
async function loadDataSequential() {
  console.time('์ˆœ์ฐจ ๋กœ๋”ฉ');
  
  const userData = await fetchUserData();
  const productData = await fetchProducts();
  const weatherData = await fetchWeather();
  
  console.timeEnd('์ˆœ์ฐจ ๋กœ๋”ฉ');
  return { userData, productData, weatherData };
}

// ๋ณ‘๋ ฌ ์‹คํ–‰ (๋น ๋ฆ„)
async function loadDataParallel() {
  console.time('๋ณ‘๋ ฌ ๋กœ๋”ฉ');
  
  // ๋ชจ๋“  ์š”์ฒญ์„ ๋™์‹œ์— ์‹œ์ž‘
  const userPromise = fetchUserData();
  const productPromise = fetchProducts();
  const weatherPromise = fetchWeather();
  
  // ๋ชจ๋“  ๊ฒฐ๊ณผ ๊ธฐ๋‹ค๋ฆฌ๊ธฐ
  const [userData, productData, weatherData] = await Promise.all([
    userPromise, productPromise, weatherPromise
  ]);
  
  console.timeEnd('๋ณ‘๋ ฌ ๋กœ๋”ฉ');
  return { userData, productData, weatherData };
}

// ๋” ๊ฐ„๊ฒฐํ•œ ๋ฐฉ๋ฒ•
async function loadDataParallelConcise() {
  console.time('๋ณ‘๋ ฌ ๋กœ๋”ฉ (๊ฐ„๊ฒฐ)');
  
  const [userData, productData, weatherData] = await Promise.all([
    fetchUserData(),
    fetchProducts(),
    fetchWeather()
  ]);
  
  console.timeEnd('๋ณ‘๋ ฌ ๋กœ๋”ฉ (๊ฐ„๊ฒฐ)');
  return { userData, productData, weatherData };
}
    

7.2 ๋ฉ”๋ชจ์ด์ œ์ด์…˜๊ณผ ์บ์‹ฑ

๋™์ผํ•œ ๋น„๋™๊ธฐ ์ž‘์—…์˜ ๊ฒฐ๊ณผ๋ฅผ ์บ์‹ฑํ•˜๋ฉด ์„ฑ๋Šฅ์„ ํฌ๊ฒŒ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์–ด:


// ๋ฉ”๋ชจ์ด์ œ์ด์…˜ ํ•จ์ˆ˜
function memoizeAsync(fn) {
  const cache = new Map();
  
  return async function(...args) {
    const key = JSON.stringify(args);
    
    if (cache.has(key)) {
      console.log('์บ์‹œ์—์„œ ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜');
      return cache.get(key);
    }
    
    console.log('์ƒˆ๋กœ์šด ๊ฒฐ๊ณผ ๊ณ„์‚ฐ ์ค‘');
    const result = await fn(...args);
    cache.set(key, result);
    return result;
  };
}

// ์‚ฌ์šฉ ์˜ˆ
const fetchUserMemoized = memoizeAsync(async (userId) => {
  const response = await fetch(`https://api.example.com/users/${userId}`);
  return response.json();
});

// ์ฒซ ๋ฒˆ์งธ ํ˜ธ์ถœ: API ์š”์ฒญ ๋ฐœ์ƒ
fetchUserMemoized(123).then(user => console.log('์‚ฌ์šฉ์ž 1:', user));

// ๋‘ ๋ฒˆ์งธ ํ˜ธ์ถœ: ์บ์‹œ์—์„œ ๋ฐ˜ํ™˜ (API ์š”์ฒญ ์—†์Œ)
setTimeout(() => {
  fetchUserMemoized(123).then(user => console.log('์‚ฌ์šฉ์ž 2 (์บ์‹œ๋จ):', user));
}, 2000);
    

7.3 ์ง€์—ฐ ๋กœ๋”ฉ๊ณผ ํ”„๋ฆฌํŽ˜์นญ

ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋งŒ ๋จผ์ € ๋กœ๋“œํ•˜๊ณ , ๋‚˜๋จธ์ง€๋Š” ํ•„์š”ํ•  ๋•Œ ๋˜๋Š” ๋ฏธ๋ฆฌ ์˜ˆ์ธกํ•˜์—ฌ ๋กœ๋“œํ•˜๋Š” ์ „๋žต:


// ์ง€์—ฐ ๋กœ๋”ฉ ๊ตฌํ˜„
class DataLoader {
  constructor() {
    this.data = {};
    this.loading = {};
  }
  
  // ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ (์ด๋ฏธ ๋กœ๋”ฉ ์ค‘์ด๋ฉด ๊ธฐ์กด Promise ๋ฐ˜ํ™˜)
  async load(key, fetchFn) {
    // ์ด๋ฏธ ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ์œผ๋ฉด ๋ฐ”๋กœ ๋ฐ˜ํ™˜
    if (this.data[key]) {
      console.log(`${key} ๋ฐ์ดํ„ฐ ์ด๋ฏธ ๋กœ๋“œ๋จ`);
      return this.data[key];
    }
    
    // ์ด๋ฏธ ๋กœ๋”ฉ ์ค‘์ด๋ฉด ๊ธฐ์กด Promise ๋ฐ˜ํ™˜
    if (this.loading[key]) {
      console.log(`${key} ๋ฐ์ดํ„ฐ ๋กœ๋”ฉ ์ค‘, ๊ธฐ์กด ์š”์ฒญ์— ์—ฐ๊ฒฐ`);
      return this.loading[key];
    }
    
    // ์ƒˆ๋กœ ๋กœ๋”ฉ ์‹œ์ž‘
    console.log(`${key} ๋ฐ์ดํ„ฐ ๋กœ๋”ฉ ์‹œ์ž‘`);
    this.loading[key] = fetchFn().then(result => {
      this.data[key] = result;
      delete this.loading[key];
      return result;
    });
    
    return this.loading[key];
  }
  
  // ๋ฏธ๋ฆฌ ๋ฐ์ดํ„ฐ ๋กœ๋“œ (ํ”„๋ฆฌํŽ˜์นญ)
  prefetch(key, fetchFn) {
    if (!this.data[key] && !this.loading[key]) {
      console.log(`${key} ๋ฐ์ดํ„ฐ ํ”„๋ฆฌํŽ˜์นญ`);
      this.load(key, fetchFn).catch(error => {
        console.warn(`ํ”„๋ฆฌํŽ˜์นญ ์‹คํŒจ (${key}):`, error);
      });
    }
  }
}

// ์‚ฌ์šฉ ์˜ˆ
const loader = new DataLoader();

// ํ•„์ˆ˜ ๋ฐ์ดํ„ฐ ์ฆ‰์‹œ ๋กœ๋“œ
async function loadInitialData() {
  const userData = await loader.load('user', () => 
    fetch('https://api.example.com/user').then(r => r.json())
  );
  
  // ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ ํ‘œ์‹œ
  displayUserInfo(userData);
  
  // ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ ๋กœ๋“œ ํ›„ ๊ด€๋ จ ๋ฐ์ดํ„ฐ ๋ฏธ๋ฆฌ ๋กœ๋“œ
  loader.prefetch('notifications', () => 
    fetch('https://api.example.com/notifications').then(r => r.json())
  );
  
  loader.prefetch('recommendations', () => 
    fetch('https://api.example.com/recommendations').then(r => r.json())
  );
}

// ์‚ฌ์šฉ์ž๊ฐ€ ์•Œ๋ฆผ ํƒญ์„ ํด๋ฆญํ–ˆ์„ ๋•Œ
async function showNotifications() {
  const notifications = await loader.load('notifications', () => 
    fetch('https://api.example.com/notifications').then(r => r.json())
  );
  
  displayNotifications(notifications);
}
    

7.4 ๋น„๋™๊ธฐ ์ž‘์—… ๋ฐฐ์น˜ ์ฒ˜๋ฆฌ

์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ž‘์€ ๋น„๋™๊ธฐ ์ž‘์—…์„ ํ•˜๋‚˜์˜ ํฐ ์ž‘์—…์œผ๋กœ ๋ฐฐ์น˜ ์ฒ˜๋ฆฌํ•˜๋ฉด ๋„คํŠธ์›Œํฌ ์˜ค๋ฒ„ํ—ค๋“œ๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ์–ด:


// ๋ฐฐ์น˜ ์ฒ˜๋ฆฌ ์œ ํ‹ธ๋ฆฌํ‹ฐ
class BatchProcessor {
  constructor(processFn, options = {}) {
    this.processFn = processFn;
    this.maxBatchSize = options.maxBatchSize || 100;
    this.maxWaitMs = options.maxWaitMs || 50;
    this.items = [];
    this.pendingPromises = new Map();
    this.timeout = null;
  }
  
  // ์•„์ดํ…œ ์ถ”๊ฐ€ ๋ฐ Promise ๋ฐ˜ํ™˜
  add(item) {
    const itemId = Math.random().toString(36).substr(2, 9);
    
    // ์ƒˆ Promise ์ƒ์„ฑ ๋ฐ ์ €์žฅ
    const promise = new Promise((resolve, reject) => {
      this.pendingPromises.set(itemId, { resolve, reject });
    });
    
    // ์•„์ดํ…œ์„ ๋ฐฐ์น˜์— ์ถ”๊ฐ€
    this.items.push({ id: itemId, data: item });
    
    // ํƒ€์ด๋จธ ์„ค์ • (์•„์ง ์—†๋Š” ๊ฒฝ์šฐ)
    if (!this.timeout) {
      this.timeout = setTimeout(() => this.processItems(), this.maxWaitMs);
    }
    
    // ๋ฐฐ์น˜ ํฌ๊ธฐ๊ฐ€ ์ตœ๋Œ€์— ๋„๋‹ฌํ•˜๋ฉด ์ฆ‰์‹œ ์ฒ˜๋ฆฌ
    if (this.items.length >= this.maxBatchSize) {
      clearTimeout(this.timeout);
      this.timeout = null;
      this.processItems();
    }
    
    return promise;
  }
  
  // ๋ฐฐ์น˜ ์ฒ˜๋ฆฌ ์‹คํ–‰
  async processItems() {
    const itemsToProcess = [...this.items];
    this.items = [];
    this.timeout = null;
    
    if (itemsToProcess.length === 0) return;
    
    try {
      console.log(`${itemsToProcess.length}๊ฐœ ์•„์ดํ…œ ๋ฐฐ์น˜ ์ฒ˜๋ฆฌ ์ค‘...`);
      
      // ๋ฐฐ์น˜ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜ ํ˜ธ์ถœ
      const results = await this.processFn(itemsToProcess.map(item => item.data));
      
      // ๊ฐ Promise ํ•ด๊ฒฐ
      itemsToProcess.forEach((item, index) => {
        const { resolve } = this.pendingPromises.get(item.id);
        resolve(results[index]);
        this.pendingPromises.delete(item.id);
      });
    } catch (error) {
      console.error('๋ฐฐ์น˜ ์ฒ˜๋ฆฌ ์‹คํŒจ:', error);
      
      // ๋ชจ๋“  Promise ๊ฑฐ๋ถ€
      itemsToProcess.forEach(item => {
        const { reject } = this.pendingPromises.get(item.id);
        reject(error);
        this.pendingPromises.delete(item.id);
      });
    }
  }
}

// ์‚ฌ์šฉ ์˜ˆ: ์—ฌ๋Ÿฌ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ํ•œ ๋ฒˆ์— ๊ฐ€์ ธ์˜ค๊ธฐ
const userBatchLoader = new BatchProcessor(async (userIds) => {
  // ์—ฌ๋Ÿฌ ID๋ฅผ ํ•œ ๋ฒˆ์— ์š”์ฒญ
  const response = await fetch('https://api.example.com/users/batch', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ ids: userIds })
  });
  
  const users = await response.json();
  
  // ๊ฐ ID์— ๋Œ€ํ•œ ๊ฒฐ๊ณผ ๋งคํ•‘
  return userIds.map(id => users.find(user => user.id === id) || null);
}, { maxBatchSize: 50, maxWaitMs: 100 });

// ๊ฐœ๋ณ„ ์‚ฌ์šฉ์ž ๋กœ๋“œ ํ•จ์ˆ˜
async function loadUser(userId) {
  return userBatchLoader.add(userId);
}

// ์—ฌ๋Ÿฌ ์‚ฌ์šฉ์ž ๋กœ๋“œ (๋‚ด๋ถ€์ ์œผ๋กœ ๋ฐฐ์น˜ ์ฒ˜๋ฆฌ๋จ)
loadUser(1).then(user => console.log('์‚ฌ์šฉ์ž 1:', user));
loadUser(2).then(user => console.log('์‚ฌ์šฉ์ž 2:', user));
loadUser(3).then(user => console.log('์‚ฌ์šฉ์ž 3:', user));
// ... ๋” ๋งŽ์€ ์š”์ฒญ๋“ค ...
    

7.5 ๋น„๋™๊ธฐ ์ž‘์—… ์šฐ์„ ์ˆœ์œ„ ์ง€์ •

2025๋…„์—๋Š” ์ค‘์š”ํ•œ ์ž‘์—…์— ์šฐ์„ ์ˆœ์œ„๋ฅผ ๋ถ€์—ฌํ•˜๋Š” ๊ฒƒ์ด ๋” ์ค‘์š”ํ•ด์กŒ์–ด:


// ์šฐ์„ ์ˆœ์œ„ ํ ๊ตฌํ˜„
class PriorityQueue {
  constructor() {
    this.highPriority = [];
    this.normalPriority = [];
    this.lowPriority = [];
    this.isProcessing = false;
  }
  
  // ์ž‘์—… ์ถ”๊ฐ€
  enqueue(task, priority = 'normal') {
    switch (priority) {
      case 'high':
        this.highPriority.push(task);
        break;
      case 'low':
        this.lowPriority.push(task);
        break;
      default:
        this.normalPriority.push(task);
    }
    
    // ํ ์ฒ˜๋ฆฌ ์‹œ์ž‘
    if (!this.isProcessing) {
      this.processQueue();
    }
  }
  
  // ํ ์ฒ˜๋ฆฌ
  async processQueue() {
    if (this.isProcessing) return;
    
    this.isProcessing = true;
    
    while (
      this.highPriority.length > 0 || 
      this.normalPriority.length > 0 || 
      this.lowPriority.length > 0
    ) {
      let task;
      
      // ์šฐ์„ ์ˆœ์œ„์— ๋”ฐ๋ผ ์ž‘์—… ์„ ํƒ
      if (this.highPriority.length > 0) {
        task = this.highPriority.shift();
      } else if (this.normalPriority.length > 0) {
        task = this.normalPriority.shift();
      } else {
        task = this.lowPriority.shift();
      }
      
      try {
        await task();
      } catch (error) {
        console.error('์ž‘์—… ์‹คํ–‰ ์˜ค๋ฅ˜:', error);
      }
      
      // ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋‹ค๋ฅธ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ์ž ์‹œ ์–‘๋ณด
      await new Promise(resolve => setTimeout(resolve, 0));
    }
    
    this.isProcessing = false;
  }
}

// ์‚ฌ์šฉ ์˜ˆ
const taskQueue = new PriorityQueue();

// ์ค‘์š”ํ•œ ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ ๋กœ๋“œ (๋†’์€ ์šฐ์„ ์ˆœ์œ„)
taskQueue.enqueue(async () => {
  console.log('์‚ฌ์šฉ์ž ํ”„๋กœํ•„ ๋กœ๋”ฉ (๋†’์€ ์šฐ์„ ์ˆœ์œ„)');
  const userData = await fetch('/api/user').then(r => r.json());
  updateUserProfile(userData);
}, 'high');

// ๋œ ์ค‘์š”ํ•œ ๋ฐ์ดํ„ฐ ๋กœ๋“œ (๋‚ฎ์€ ์šฐ์„ ์ˆœ์œ„)
taskQueue.enqueue(async () => {
  console.log('์ถ”์ฒœ ์ƒํ’ˆ ๋กœ๋”ฉ (๋‚ฎ์€ ์šฐ์„ ์ˆœ์œ„)');
  const recommendations = await fetch('/api/recommendations').then(r => r.json());
  updateRecommendations(recommendations);
}, 'low');

// ์ผ๋ฐ˜ ์šฐ์„ ์ˆœ์œ„ ์ž‘์—…
taskQueue.enqueue(async () => {
  console.log('์•Œ๋ฆผ ๋กœ๋”ฉ (์ผ๋ฐ˜ ์šฐ์„ ์ˆœ์œ„)');
  const notifications = await fetch('/api/notifications').then(r => r.json());
  updateNotifications(notifications);
});
    

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

8. ๋งˆ๋ฌด๋ฆฌ ๋ฐ ์ถ”๊ฐ€ ์ž๋ฃŒ ๐Ÿ“š

์—ฌ๊ธฐ๊นŒ์ง€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ์„ธ๊ณ„๋ฅผ ํ•จ๊ป˜ ํƒํ—˜ํ•ด๋ดค์–ด! ์ฝœ๋ฐฑ๋ถ€ํ„ฐ Promise, async/await๊นŒ์ง€, ๊ทธ๋ฆฌ๊ณ  2025๋…„์˜ ์ตœ์‹  ํŠธ๋ Œ๋“œ์™€ ์„ฑ๋Šฅ ์ตœ์ ํ™” ๊ธฐ๋ฒ•๊นŒ์ง€ ๋‹ค์–‘ํ•œ ๋‚ด์šฉ์„ ๋‹ค๋ค˜์ง€. ๐ŸŽ‰

๋ฐฐ์šด ๋‚ด์šฉ ์š”์•ฝ

  1. ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ๊ธฐ๋ณธ ๊ฐœ๋…๊ณผ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ์ด๋ฒคํŠธ ๋ฃจํ”„
  2. ์ฝœ๋ฐฑ ํ•จ์ˆ˜์™€ ์ฝœ๋ฐฑ ์ง€์˜ฅ์˜ ๋ฌธ์ œ์ 
  3. Promise์˜ ๊ฐœ๋…๊ณผ ์‚ฌ์šฉ๋ฒ• (then, catch, finally)
  4. ์—ฌ๋Ÿฌ Promise๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” Promise.all, Promise.race, Promise.allSettled
  5. async/await ๋ฌธ๋ฒ•์œผ๋กœ ๋” ๊น”๋”ํ•œ ๋น„๋™๊ธฐ ์ฝ”๋“œ ์ž‘์„ฑํ•˜๊ธฐ
  6. 2025๋…„ ์ตœ์‹  ๋น„๋™๊ธฐ ํŒจํ„ด๊ณผ ํŠธ๋ Œ๋“œ
  7. ๋น„๋™๊ธฐ ์ฝ”๋“œ์˜ ์„ฑ๋Šฅ ์ตœ์ ํ™” ๊ธฐ๋ฒ•

๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ํ˜„๋Œ€ ์›น ๊ฐœ๋ฐœ์˜ ํ•ต์‹ฌ์ด์•ผ. ํŠนํžˆ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์ด ์ค‘์š”ํ•œ 2025๋…„์—๋Š” ๋”์šฑ ๊ทธ๋ ‡์ง€! ์žฌ๋Šฅ๋„ท์—์„œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ด€๋ จ ์žฌ๋Šฅ์„ ๊ณต์œ ํ•˜๊ฑฐ๋‚˜ ๊ตฌ๋งคํ•  ๋•Œ, ์ด๋Ÿฐ ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์ง€์‹์€ ํฐ ๊ฒฝ์Ÿ๋ ฅ์ด ๋  ์ˆ˜ ์žˆ์–ด. ๐Ÿ˜Š

๋” ๊ณต๋ถ€ํ•˜๋ฉด ์ข‹์„ ์ฃผ์ œ๋“ค

1. ๋น„๋™๊ธฐ ์ƒํƒœ ๊ด€๋ฆฌ

Redux-Saga, MobX, Zustand ๋“ฑ์„ ์‚ฌ์šฉํ•œ ๋น„๋™๊ธฐ ์ƒํƒœ ๊ด€๋ฆฌ

2. ๋ฐ˜์‘ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ

RxJS๋ฅผ ํ™œ์šฉํ•œ ๋ณต์žกํ•œ ๋น„๋™๊ธฐ ์ด๋ฒคํŠธ ์ŠคํŠธ๋ฆผ ์ฒ˜๋ฆฌ

3. ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋น„๋™๊ธฐ

Node.js์—์„œ์˜ ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ๊ณผ ์ด๋ฒคํŠธ ๋ฃจํ”„

4. ๋น„๋™๊ธฐ ํ…Œ์ŠคํŠธ

Jest, Mocha ๋“ฑ์„ ์‚ฌ์šฉํ•œ ๋น„๋™๊ธฐ ์ฝ”๋“œ ํ…Œ์ŠคํŠธ ๋ฐฉ๋ฒ•

์ถ”์ฒœ ์ž๋ฃŒ

๐Ÿ“˜ ๋„์„œ

  • "JavaScript: The Good Parts" - Douglas Crockford
  • "You Don't Know JS: Async & Performance" - Kyle Simpson
  • "JavaScript Patterns" - Stoyan Stefanov

๐ŸŒ ์›น์‚ฌ์ดํŠธ

  • MDN Web Docs - JavaScript ๊ฐ€์ด๋“œ
  • JavaScript.info - ํ˜„๋Œ€ JavaScript ํŠœํ† ๋ฆฌ์–ผ
  • ์žฌ๋Šฅ๋„ท - ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ด€๋ จ ๊ฐ•์˜ ๋ฐ ํ”„๋กœ์ ํŠธ

๐Ÿ“บ ๋™์˜์ƒ ๊ฐ•์˜

  • Udemy - "JavaScript: Understanding the Weird Parts"
  • Frontend Masters - "JavaScript: The Hard Parts"
  • YouTube - "Async JS Crash Course"

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ๊ณ„์†ํ•ด์„œ ๋ฐœ์ „ํ•˜๊ณ  ์žˆ์–ด. ๊พธ์ค€ํžˆ ๊ณต๋ถ€ํ•˜๊ณ  ์‹ค์Šตํ•˜๋ฉด์„œ ์ตœ์‹  ํŠธ๋ Œ๋“œ๋ฅผ ๋”ฐ๋ผ๊ฐ€๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ด. ์ด ๊ธ€์ด ๋„ˆ์˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—ฌ์ •์— ๋„์›€์ด ๋˜์—ˆ๊ธธ ๋ฐ”๋ผ! ๐Ÿš€

ํ•จ๊ป˜ ์„ฑ์žฅํ•ด์š”!

๋” ๋งŽ์€ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์ง€์‹๊ณผ ์žฌ๋Šฅ์„ ๊ณต์œ ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์žฌ๋Šฅ๋„ท์„ ๋ฐฉ๋ฌธํ•ด๋ณด์„ธ์š”. ๋‹ค์–‘ํ•œ ๊ฐœ๋ฐœ์ž๋“ค๊ณผ ์ง€์‹์„ ๋‚˜๋ˆ„๊ณ , ์ƒˆ๋กœ์šด ๊ธฐ์ˆ ์„ ๋ฐฐ์šธ ์ˆ˜ ์žˆ๋Š” ๊ธฐํšŒ๊ฐ€ ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค! ๐Ÿ’ป

1. ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด๋ž€? ๐Ÿค”

๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด ๋ญ”์ง€ ์นœ๊ตฌ์—๊ฒŒ ์„ค๋ช…ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ด๋ณผ๊นŒ? ์•„์ฃผ ๊ฐ„๋‹จํ•ด! ๋น„๋™๊ธฐ๋Š” '๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  ๋‹ค๋ฅธ ์ผ์„ ํ•˜๋Š” ๊ฒƒ'์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋ผ.

์˜ˆ๋ฅผ ๋“ค์–ด๋ณผ๊ฒŒ. ๋„Œ ์นดํŽ˜์—์„œ ์ปคํ”ผ๋ฅผ ์ฃผ๋ฌธํ–ˆ์–ด. ๋™๊ธฐ์  ์„ธ๊ณ„์—์„  ์ปคํ”ผ๊ฐ€ ๋‚˜์˜ฌ ๋•Œ๊นŒ์ง€ ์นด์šดํ„ฐ ์•ž์—์„œ ๊ผผ์ง ๋ชปํ•˜๊ณ  ๊ธฐ๋‹ค๋ ค์•ผ ํ•ด. ๊ทผ๋ฐ ๋น„๋™๊ธฐ์  ์„ธ๊ณ„์—์„ ? ์ฃผ๋ฌธํ•˜๊ณ  ์ง„๋™๋ฒจ์„ ๋ฐ›์€ ๋‹ค์Œ, ์ž๋ฆฌ์— ์•‰์•„์„œ ๋‹ค๋ฅธ ์ผ(๋…ธํŠธ๋ถ ์ผœ๊ธฐ, ์นœ๊ตฌ๋ž‘ ๋Œ€ํ™”ํ•˜๊ธฐ ๋“ฑ)์„ ํ•  ์ˆ˜ ์žˆ์ง€! ์ปคํ”ผ๊ฐ€ ์ค€๋น„๋˜๋ฉด ๋ฒจ์ด ์šธ๋ฆฌ๊ณ , ๊ทธ๋•Œ ๊ฐ€์„œ ์ปคํ”ผ๋ฅผ ๋ฐ›์œผ๋ฉด ๋ผ. ์ด๊ฒŒ ๋ฐ”๋กœ ๋น„๋™๊ธฐ์•ผ! ๐Ÿ‘

1.1 ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์™€ ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ ์–ธ์–ด์•ผ. ์ฆ‰, ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์˜ ์ž‘์—…๋งŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด. ๊ทธ๋Ÿฐ๋ฐ ์–ด๋–ป๊ฒŒ ์—ฌ๋Ÿฌ ์ž‘์—…์„ ๋™์‹œ์— ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ผ๊นŒ? ๊ทธ ๋น„๋ฐ€์€ ๋ฐ”๋กœ '์ด๋ฒคํŠธ ๋ฃจํ”„'์— ์žˆ์–ด!

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋Ÿฐํƒ€์ž„ Call Stack ์‹คํ–‰ ์ค‘์ธ ์ฝ”๋“œ Web APIs Callback Queue Event Loop ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ด๋ฒคํŠธ ๋ฃจํ”„ ๋ชจ๋ธ

์ด๋ฒคํŠธ ๋ฃจํ”„๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๋น„๋™๊ธฐ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ํ•ต์‹ฌ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด์•ผ. ์œ„ ๊ทธ๋ฆผ์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋“ฏ์ด, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ์ฝœ ์Šคํƒ์—์„œ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๊ณ , ๋น„๋™๊ธฐ ์ž‘์—…์€ Web API๋กœ ๋„˜๊ฒจ. ์ž‘์—…์ด ์™„๋ฃŒ๋˜๋ฉด ์ฝœ๋ฐฑ ํ์— ๋“ค์–ด๊ฐ€๊ณ , ์ด๋ฒคํŠธ ๋ฃจํ”„๊ฐ€ ์ฝœ ์Šคํƒ์ด ๋น„์—ˆ์„ ๋•Œ ์ฝœ๋ฐฑ์„ ์‹คํ–‰ํ•ด์ฃผ๋Š” ๊ฑฐ์ง€! ๐Ÿ˜Š

1.2 ๋™๊ธฐ vs ๋น„๋™๊ธฐ ์ฝ”๋“œ ๋น„๊ต

๋™๊ธฐ ์ฝ”๋“œ ์˜ˆ์‹œ:


console.log("์ž‘์—… 1 ์‹œ์ž‘");
// ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋Š” ์ž‘์—…
for (let i = 0; i < 1000000000; i++) {
  // ๋ฌด๊ฑฐ์šด ๊ณ„์‚ฐ
}
console.log("์ž‘์—… 1 ์™„๋ฃŒ");
console.log("์ž‘์—… 2 ์‹œ์ž‘");
        

๋น„๋™๊ธฐ ์ฝ”๋“œ ์˜ˆ์‹œ:


console.log("์ž‘์—… 1 ์‹œ์ž‘");
// ๋น„๋™๊ธฐ ์ž‘์—… (์‹œ๊ฐ„์ด ๊ฑธ๋ฆฌ์ง€๋งŒ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š์Œ)
setTimeout(() => {
  console.log("์ž‘์—… 1 ์™„๋ฃŒ");
}, 2000);
console.log("์ž‘์—… 2 ์‹œ์ž‘"); // ์ž‘์—… 1์ด ๋๋‚˜๊ธฐ ์ „์— ์‹คํ–‰๋จ!
        

๋น„๋™๊ธฐ ์ฝ”๋“œ์˜ ์žฅ์ ์€ ๋ญ˜๊นŒ? ๋ฐ”๋กœ ํšจ์œจ์„ฑ์ด์•ผ! ํŠนํžˆ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ƒํ™ฉ์—์„œ ๋น›์„ ๋ฐœํ•˜์ง€:

  1. ๋„คํŠธ์›Œํฌ ์š”์ฒญ (API ํ˜ธ์ถœ, ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ)
  2. ํŒŒ์ผ ์‹œ์Šคํ…œ ์ž‘์—… (ํŒŒ์ผ ์ฝ๊ธฐ/์“ฐ๊ธฐ)
  3. ํƒ€์ด๋จธ ๋ฐ ์ธํ„ฐ๋ฒŒ (setTimeout, setInterval)
  4. ์‚ฌ์šฉ์ž ์ž…๋ ฅ ์ฒ˜๋ฆฌ (์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ)
  5. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ฟผ๋ฆฌ

2. ์ฝœ๋ฐฑ ํ•จ์ˆ˜์™€ ์ฝœ๋ฐฑ ์ง€์˜ฅ ๐Ÿ˜ฑ

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

์ฝœ๋ฐฑ ํ•จ์ˆ˜๋Š” ๋งˆ์น˜ ํ”ผ์ž๋ฅผ ์ฃผ๋ฌธํ•œ ํ›„ "ํ”ผ์ž๊ฐ€ ์ค€๋น„๋˜๋ฉด ์ด ๋ฒˆํ˜ธ๋กœ ์ „ํ™”ํ•ด์ฃผ์„ธ์š”"๋ผ๊ณ  ๋งํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์•„. ๋„ˆ๋Š” ์ „ํ™”๊ฐ€ ์˜ฌ ๋•Œ๊นŒ์ง€ ๋‹ค๋ฅธ ์ผ์„ ํ•  ์ˆ˜ ์žˆ๊ณ , ์ „ํ™”(์ฝœ๋ฐฑ)๊ฐ€ ์˜ค๋ฉด ๊ทธ๋•Œ ํ”ผ์ž๋ฅผ ๋ฐ›์œผ๋Ÿฌ ๊ฐ€๋Š” ๊ฑฐ์ง€! ๐Ÿ•

2.1 ๊ฐ„๋‹จํ•œ ์ฝœ๋ฐฑ ์˜ˆ์ œ


function downloadFile(url, callback) {
  console.log(`${url}์—์„œ ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ ์‹œ์ž‘...`);
  
  // ๋น„๋™๊ธฐ ์ž‘์—… ์‹œ๋ฎฌ๋ ˆ์ด์…˜ (์‹ค์ œ๋กœ๋Š” fetch ๋“ฑ์„ ์‚ฌ์šฉ)
  setTimeout(() => {
    const fileName = url.split('/').pop();
    console.log(`${fileName} ๋‹ค์šด๋กœ๋“œ ์™„๋ฃŒ!`);
    callback(fileName); // ๋‹ค์šด๋กœ๋“œ ์™„๋ฃŒ ํ›„ ์ฝœ๋ฐฑ ์‹คํ–‰
  }, 2000);
}

downloadFile('https://example.com/photo.jpg', (fileName) => {
  console.log(`๋‹ค์šด๋กœ๋“œํ•œ ${fileName}์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.`);
});

console.log("๋‹ค์šด๋กœ๋“œ ๋ช…๋ น ํ›„ ์ฆ‰์‹œ ์‹คํ–‰๋˜๋Š” ์ฝ”๋“œ");
    

์œ„ ์ฝ”๋“œ์˜ ์‹คํ–‰ ์ˆœ์„œ๋Š” ์–ด๋–ป๊ฒŒ ๋ ๊นŒ? ๐Ÿค”

  1. "https://example.com/photo.jpg์—์„œ ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ ์‹œ์ž‘..." ์ถœ๋ ฅ
  2. "๋‹ค์šด๋กœ๋“œ ๋ช…๋ น ํ›„ ์ฆ‰์‹œ ์‹คํ–‰๋˜๋Š” ์ฝ”๋“œ" ์ถœ๋ ฅ
  3. 2์ดˆ ํ›„ "photo.jpg ๋‹ค์šด๋กœ๋“œ ์™„๋ฃŒ!" ์ถœ๋ ฅ
  4. "๋‹ค์šด๋กœ๋“œํ•œ photo.jpg์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค." ์ถœ๋ ฅ

์ด์ฒ˜๋Ÿผ ๋น„๋™๊ธฐ ์ž‘์—…์€ ์ฝ”๋“œ์˜ ์‹คํ–‰ ์ˆœ์„œ๊ฐ€ ์ž‘์„ฑ๋œ ์ˆœ์„œ์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์–ด. ์ด๊ฒŒ ๋ฐ”๋กœ ๋น„๋™๊ธฐ์˜ ํŠน์ง•์ด์ง€!

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

๊ทธ๋Ÿฐ๋ฐ ๋น„๋™๊ธฐ ์ž‘์—…์ด ์—ฌ๋Ÿฌ ๊ฐœ ์ค‘์ฒฉ๋˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ? ๋ฐ”๋กœ ์ฝœ๋ฐฑ ์ง€์˜ฅ(Callback Hell)์ด ํŽผ์ณ์ ธ! ๐Ÿ˜ฑ

์ฒซ ๋ฒˆ์งธ ๋น„๋™๊ธฐ ์ž‘์—…() ๋‘ ๋ฒˆ์งธ ๋น„๋™๊ธฐ ์ž‘์—…() ์„ธ ๋ฒˆ์งธ ๋น„๋™๊ธฐ ์ž‘์—…() ๋„ค ๋ฒˆ์งธ ๋น„๋™๊ธฐ ์ž‘์—…() ๋‹ค์„ฏ ๋ฒˆ์งธ ๋น„๋™๊ธฐ ์ž‘์—…() ์ฝœ๋ฐฑ ์ง€์˜ฅ (Callback Hell) ๋“ค์—ฌ์“ฐ๊ธฐ๊ฐ€ ๊ณ„์† ๊นŠ์–ด์ง€๋Š” ์ฝ”๋“œ ๊ตฌ์กฐ

์‹ค์ œ ์ฝ”๋“œ๋กœ ๋ณด๋ฉด ์ด๋Ÿฐ ๋ชจ์Šต์ด์•ผ:


// ์ฝœ๋ฐฑ ์ง€์˜ฅ์˜ ์˜ˆ์‹œ
getUserData(userId, (userData) => {
  getPostsByUser(userData.id, (posts) => {
    getCommentsForLatestPost(posts[0].id, (comments) => {
      getLikesForComments(comments, (likes) => {
        getUsersWhoLiked(likes, (users) => {
          // ์—ฌ๊ธฐ์„œ ๋ญ”๊ฐ€๋ฅผ ํ•˜๋ ค๋ฉด...
          // ๋“ค์—ฌ์“ฐ๊ธฐ๊ฐ€ ๊ณ„์† ๊นŠ์–ด์ง€๊ณ ...
          // ์ฝ”๋“œ๊ฐ€ ์ ์  ๋ณต์žกํ•ด์ง€๊ณ ...
          console.log("๋“œ๋””์–ด ์›ํ•˜๋Š” ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผ!", users);
        }, (error) => {
          console.error("์ข‹์•„์š” ๋ˆ„๋ฅธ ์‚ฌ์šฉ์ž ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ ์‹คํŒจ", error);
        });
      }, (error) => {
        console.error("์ข‹์•„์š” ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ ์‹คํŒจ", error);
      });
    }, (error) => {
      console.error("๋Œ“๊ธ€ ๊ฐ€์ ธ์˜ค๊ธฐ ์‹คํŒจ", error);
    });
  }, (error) => {
    console.error("ํฌ์ŠคํŠธ ๊ฐ€์ ธ์˜ค๊ธฐ ์‹คํŒจ", error);
  });
}, (error) => {
  console.error("์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ ์‹คํŒจ", error);
});
    

์ด๋Ÿฐ ์ฝ”๋“œ๋Š” ์ฝ๊ธฐ ์–ด๋ ต๊ณ , ์œ ์ง€๋ณด์ˆ˜ํ•˜๊ธฐ ์–ด๋ ต๊ณ , ์—๋Ÿฌ ์ฒ˜๋ฆฌ๋„ ๋ณต์žกํ•ด์ ธ. ์ด๋Ÿฐ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋“ฑ์žฅํ•œ ๊ฒƒ์ด ๋ฐ”๋กœ Promise์•ผ! ๐ŸŽ‰

3. Promise ์™„๋ฒฝ ์ดํ•ดํ•˜๊ธฐ ๐Ÿค

Promise๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ๋น„๋™๊ธฐ ์ž‘์—…์˜ ์ตœ์ข… ์™„๋ฃŒ(๋˜๋Š” ์‹คํŒจ)์™€ ๊ทธ ๊ฒฐ๊ณผ๊ฐ’์„ ๋‚˜ํƒ€๋‚ด๋Š” ๊ฐ์ฒด์•ผ. ์‰ฝ๊ฒŒ ๋งํ•˜๋ฉด, ๋ฏธ๋ž˜์— ์™„๋ฃŒ๋  ์ž‘์—…์˜ ๊ฒฐ๊ณผ๋ฅผ ์•ฝ์†(promise)ํ•˜๋Š” ๊ฐ์ฒด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋ผ!

Promise๋ฅผ ํ˜„์‹ค์— ๋น„์œ ํ•˜์ž๋ฉด ๋ ˆ์Šคํ† ๋ž‘์—์„œ ์Œ์‹์„ ์ฃผ๋ฌธํ•œ ํ›„ ๋ฐ›๋Š” '์ฃผ๋ฌธ ๋ฒˆํ˜ธํ‘œ'์™€ ๊ฐ™์•„. ๊ทธ ๋ฒˆํ˜ธํ‘œ๋Š” "์Œ์‹์ด ์ค€๋น„๋˜๋ฉด ์ด ๋ฒˆํ˜ธ๋ฅผ ํ˜ธ์ถœํ• ๊ฒŒ์š”"๋ผ๋Š” ์•ฝ์†์ด์ง€. ๋„ˆ๋Š” ๊ทธ ๋ฒˆํ˜ธํ‘œ๋ฅผ ๋“ค๊ณ  ๋‹ค๋ฅธ ์ผ์„ ํ•  ์ˆ˜ ์žˆ๊ณ , ๋ฒˆํ˜ธ๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด(Promise๊ฐ€ ์ดํ–‰๋˜๋ฉด) ์Œ์‹์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์–ด! ๐Ÿ”

3.1 Promise์˜ 3๊ฐ€์ง€ ์ƒํƒœ

Promise๋Š” ํ•ญ์ƒ ๋‹ค์Œ ์„ธ ๊ฐ€์ง€ ์ƒํƒœ ์ค‘ ํ•˜๋‚˜์•ผ:

1. Pending (๋Œ€๊ธฐ)

์ดˆ๊ธฐ ์ƒํƒœ, ์•„์ง ์ž‘์—…์ด ์™„๋ฃŒ๋˜์ง€ ์•Š์Œ

2. Fulfilled (์ดํ–‰)

์ž‘์—…์ด ์„ฑ๊ณต์ ์œผ๋กœ ์™„๋ฃŒ๋จ

3. Rejected (๊ฑฐ๋ถ€)

์ž‘์—…์ด ์‹คํŒจํ•จ

Pending Fulfilled Rejected resolve() reject() Promise ์ƒํƒœ ๋‹ค์ด์–ด๊ทธ๋žจ

3.2 Promise ์ƒ์„ฑํ•˜๊ธฐ

Promise ๊ฐ์ฒด๋Š” new Promise() ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋งŒ๋“ค์–ด. ์ด ์ƒ์„ฑ์ž๋Š” executor๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ์ธ์ž๋กœ ๋ฐ›์•„.


const myPromise = new Promise((resolve, reject) => {
  // ๋น„๋™๊ธฐ ์ž‘์—… ์ˆ˜ํ–‰
  const success = true; // ์ž‘์—… ์„ฑ๊ณต ์—ฌ๋ถ€ (์˜ˆ์‹œ)
  
  if (success) {
    // ์ž‘์—…์ด ์„ฑ๊ณตํ•˜๋ฉด resolve ํ˜ธ์ถœ
    resolve('์ž‘์—… ์„ฑ๊ณต! ์—ฌ๊ธฐ ๊ฒฐ๊ณผ๊ฐ’์ด์•ผ.');
  } else {
    // ์ž‘์—…์ด ์‹คํŒจํ•˜๋ฉด reject ํ˜ธ์ถœ
    reject(new Error('์ž‘์—… ์‹คํŒจ! ์—ฌ๊ธฐ ์—๋Ÿฌ ์ •๋ณด์•ผ.'));
  }
});
    

์‹ค์ œ ์˜ˆ์ œ๋ฅผ ํ†ตํ•ด Promise๋ฅผ ๋งŒ๋“ค์–ด๋ณผ๊นŒ?


// ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ๋ฅผ Promise๋กœ ๊ตฌํ˜„
function downloadFilePromise(url) {
  return new Promise((resolve, reject) => {
    console.log(`${url}์—์„œ ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ ์‹œ์ž‘...`);
    
    // ๋น„๋™๊ธฐ ์ž‘์—… ์‹œ๋ฎฌ๋ ˆ์ด์…˜
    setTimeout(() => {
      const random = Math.random();
      
      if (random > 0.3) { // 70% ํ™•๋ฅ ๋กœ ์„ฑ๊ณต
        const fileName = url.split('/').pop();
        console.log(`${fileName} ๋‹ค์šด๋กœ๋“œ ์™„๋ฃŒ!`);
        resolve(fileName); // ์„ฑ๊ณต ์‹œ ํŒŒ์ผ๋ช… ๋ฐ˜ํ™˜
      } else {
        reject(new Error('๋„คํŠธ์›Œํฌ ์˜ค๋ฅ˜๋กœ ๋‹ค์šด๋กœ๋“œ ์‹คํŒจ')); // ์‹คํŒจ ์‹œ ์—๋Ÿฌ ๊ฐ์ฒด ๋ฐ˜ํ™˜
      }
    }, 2000);
  });
}
    

3.3 Promise ์‚ฌ์šฉํ•˜๊ธฐ: then, catch, finally

Promise ๊ฐ์ฒด๋Š” then(), catch(), finally() ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ๊ฒฐ๊ณผ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด.


downloadFilePromise('https://example.com/photo.jpg')
  .then((fileName) => {
    console.log(`๋‹ค์šด๋กœ๋“œํ•œ ${fileName}์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.`);
    return `์ฒ˜๋ฆฌ๋œ_${fileName}`; // ๋‹ค์Œ then์œผ๋กœ ๊ฐ’์„ ์ „๋‹ฌ
  })
  .then((processedFile) => {
    console.log(`${processedFile}์„ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.`);
    return `์ €์žฅ๋œ_${processedFile}`; // ์ฒด์ด๋‹ ๊ณ„์† ๊ฐ€๋Šฅ
  })
  .catch((error) => {
    console.error(`์˜ค๋ฅ˜ ๋ฐœ์ƒ: ${error.message}`);
  })
  .finally(() => {
    console.log('๋‹ค์šด๋กœ๋“œ ์ž‘์—… ์ข…๋ฃŒ (์„ฑ๊ณต์ด๋“  ์‹คํŒจ๋“ )');
  });

console.log('๋‹ค์šด๋กœ๋“œ ๋ช…๋ น ํ›„ ์ฆ‰์‹œ ์‹คํ–‰๋˜๋Š” ์ฝ”๋“œ');
    

์œ„ ์ฝ”๋“œ์˜ ์‹คํ–‰ ์ˆœ์„œ๋Š”:

  1. "https://example.com/photo.jpg์—์„œ ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ ์‹œ์ž‘..." ์ถœ๋ ฅ
  2. "๋‹ค์šด๋กœ๋“œ ๋ช…๋ น ํ›„ ์ฆ‰์‹œ ์‹คํ–‰๋˜๋Š” ์ฝ”๋“œ" ์ถœ๋ ฅ
  3. 2์ดˆ ํ›„, ์„ฑ๊ณต ์‹œ:
  4. "photo.jpg ๋‹ค์šด๋กœ๋“œ ์™„๋ฃŒ!" ์ถœ๋ ฅ
  5. "๋‹ค์šด๋กœ๋“œํ•œ photo.jpg์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค." ์ถœ๋ ฅ
  6. "์ฒ˜๋ฆฌ๋œ_photo.jpg์„ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค." ์ถœ๋ ฅ
  7. "๋‹ค์šด๋กœ๋“œ ์ž‘์—… ์ข…๋ฃŒ (์„ฑ๊ณต์ด๋“  ์‹คํŒจ๋“ )" ์ถœ๋ ฅ

3.4 Promise ์ฒด์ด๋‹

Promise ์ฒด์ด๋‹์€ ์—ฌ๋Ÿฌ ๋น„๋™๊ธฐ ์ž‘์—…์„ ์ˆœ์ฐจ์ ์œผ๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ์ด์•ผ. ์ฝœ๋ฐฑ ์ง€์˜ฅ์„ ํ‰ํ‰ํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ์ง€! ๐Ÿ˜Ž


// ์ฝœ๋ฐฑ ์ง€์˜ฅ์„ Promise ์ฒด์ด๋‹์œผ๋กœ ๋ณ€ํ™˜
getUserDataPromise(userId)
  .then(userData => {
    return getPostsByUserPromise(userData.id);
  })
  .then(posts => {
    return getCommentsForLatestPostPromise(posts[0].id);
  })
  .then(comments => {
    return getLikesForCommentsPromise(comments);
  })
  .then(likes => {
    return getUsersWhoLikedPromise(likes);
  })
  .then(users => {
    console.log("๋“œ๋””์–ด ์›ํ•˜๋Š” ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผ!", users);
  })
  .catch(error => {
    console.error("์–ด๋””์„ ๊ฐ€ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:", error);
  });
    

๋” ๊ฐ„๊ฒฐํ•˜๊ฒŒ ํ™”์‚ดํ‘œ ํ•จ์ˆ˜์˜ ์•”์‹œ์  ๋ฐ˜ํ™˜์„ ์‚ฌ์šฉํ•˜๋ฉด:


getUserDataPromise(userId)
  .then(userData => getPostsByUserPromise(userData.id))
  .then(posts => getCommentsForLatestPostPromise(posts[0].id))
  .then(comments => getLikesForCommentsPromise(comments))
  .then(likes => getUsersWhoLikedPromise(likes))
  .then(users => console.log("๋“œ๋””์–ด ์›ํ•˜๋Š” ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผ!", users))
  .catch(error => console.error("์–ด๋””์„ ๊ฐ€ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:", error));
    

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ฝ”๋“œ๊ฐ€ ํ›จ์”ฌ ๋” ์ฝ๊ธฐ ์‰ฝ๊ณ  ์œ ์ง€๋ณด์ˆ˜ํ•˜๊ธฐ ์‰ฌ์›Œ์ ธ! ๋“ค์—ฌ์“ฐ๊ธฐ ๋ ˆ๋ฒจ๋„ ์ผ์ •ํ•˜๊ฒŒ ์œ ์ง€๋˜๊ณ , ์—๋Ÿฌ ์ฒ˜๋ฆฌ๋„ ํ•œ ๊ณณ์—์„œ ํ•  ์ˆ˜ ์žˆ์–ด.

3.5 Promise.all, Promise.race, Promise.allSettled

์—ฌ๋Ÿฌ Promise๋ฅผ ๋™์‹œ์— ์ฒ˜๋ฆฌํ•ด์•ผ ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๋ฉ”์„œ๋“œ๋“ค์ด์•ผ:

Promise.all()

์—ฌ๋Ÿฌ Promise๋ฅผ ๋ณ‘๋ ฌ๋กœ ์‹คํ–‰ํ•˜๊ณ  ๋ชจ๋“  Promise๊ฐ€ ์„ฑ๊ณตํ–ˆ์„ ๋•Œ ๊ฒฐ๊ณผ ๋ฐฐ์—ด์„ ๋ฐ˜ํ™˜ํ•ด. ํ•˜๋‚˜๋ผ๋„ ์‹คํŒจํ•˜๋ฉด ์ „์ฒด๊ฐ€ ์‹คํŒจ๋กœ ๊ฐ„์ฃผ๋ผ.

Promise.race()

๊ฐ€์žฅ ๋จผ์ € ์™„๋ฃŒ๋˜๋Š” Promise์˜ ๊ฒฐ๊ณผ(์„ฑ๊ณต ๋˜๋Š” ์‹คํŒจ)๋ฅผ ๋ฐ˜ํ™˜ํ•ด.

Promise.allSettled()

๋ชจ๋“  Promise๊ฐ€ ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๊ณ , ๊ฐ Promise์˜ ์ƒํƒœ์™€ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ฒด ๋ฐฐ์—ด๋กœ ๋ฐ˜ํ™˜ํ•ด. (ES2020์—์„œ ์ถ”๊ฐ€)


// ์—ฌ๋Ÿฌ ํŒŒ์ผ์„ ๋™์‹œ์— ๋‹ค์šด๋กœ๋“œํ•˜๋Š” ์˜ˆ์ œ
const fileUrls = [
  'https://example.com/file1.jpg',
  'https://example.com/file2.jpg',
  'https://example.com/file3.jpg'
];

// Promise.all ์˜ˆ์ œ
Promise.all(fileUrls.map(url => downloadFilePromise(url)))
  .then(fileNames => {
    console.log('๋ชจ๋“  ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ ์™„๋ฃŒ:', fileNames);
  })
  .catch(error => {
    console.error('ํ•˜๋‚˜ ์ด์ƒ์˜ ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ ์‹คํŒจ:', error);
  });

// Promise.race ์˜ˆ์ œ
Promise.race(fileUrls.map(url => downloadFilePromise(url)))
  .then(fileName => {
    console.log('๊ฐ€์žฅ ๋จผ์ € ๋‹ค์šด๋กœ๋“œ๋œ ํŒŒ์ผ:', fileName);
  })
  .catch(error => {
    console.error('๊ฐ€์žฅ ๋จผ์ € ์‹คํŒจํ•œ ๋‹ค์šด๋กœ๋“œ:', error);
  });

// Promise.allSettled ์˜ˆ์ œ
Promise.allSettled(fileUrls.map(url => downloadFilePromise(url)))
  .then(results => {
    results.forEach((result, index) => {
      if (result.status === 'fulfilled') {
        console.log(`${fileUrls[index]} ๋‹ค์šด๋กœ๋“œ ์„ฑ๊ณต:`, result.value);
      } else {
        console.log(`${fileUrls[index]} ๋‹ค์šด๋กœ๋“œ ์‹คํŒจ:`, result.reason);
      }
    });
  });
    

์ด๋Ÿฐ ๋ฉ”์„œ๋“œ๋“ค์€ ์—ฌ๋Ÿฌ ๋น„๋™๊ธฐ ์ž‘์—…์„ ํšจ์œจ์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค˜. ํŠนํžˆ API ํ˜ธ์ถœ์ด๋‚˜ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ๊ฐ™์€ ์ž‘์—…์—์„œ ๋งค์šฐ ์œ ์šฉํ•ด! ๐Ÿš€