๐Ÿค™๐ŸปPromise Part(1) ์ •์˜ ๊ทธ๋ฆฌ๊ณ  ๋‘ ๊ฐ€์ง€ Point

๐Ÿค™๐ŸปPromise

๊ฐ€๋ณด์ž. ํ”„๋ผ๋ฏธ์“ฐ!

๐Ÿงํ”„๋ผ๋ฏธ์Šค๊ฐ€ ๋ญ?

๋น„๋™๊ธฐ๋ฅผ ๊ฐ„ํŽธํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ฃผ๋Š” Object ์ด๋‹ค.

์ •ํ•ด์ง„ ์žฅ์‹œ๊ฐ„์˜ ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ๋‚˜์„œ ์ •์ƒ์  ๊ธฐ๋Šฅ์ด ์ˆ˜ํ–‰๋˜์—ˆ๋‹ค๋ฉด ์„ฑ๊ณต ๋ฉ”์‹œ์ง€์™€ ํ•จ๊ป˜ ์ฒ˜๋ฆฌ๋œ ๊ฒฐ๊ณผ๊ฐ’์„ ์ „๋‹ฌํ•ด์ค€๋‹ค.

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•˜๋‹ค๊ฐ€ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค? ๊ทธ๋Ÿฌ๋ฉด ์—๋Ÿฌ๋ฅผ ์ „๋‹ฌํ•ด์ค€๋‹ค.

๐Ÿ˜…๋” ์‰ฝ๊ฒŒ

์•„์ดํฐ 12 ์‚ฌ์ „์˜ˆ์•ฝ ์‚ฌ์ดํŠธ๊ฐ€ ์—ด๋ ธ๋‹ค๊ณ  ํ•˜์ž.

๋‚˜๋Š” ์–ผ๋ฆฌ์–ด๋‹ตํ„ฐ๋ผ ์ƒˆ๋กœ ๋‚˜์˜ค๋Š” ๊ธฐ๊ณ„๋ฅผ ์ฐธ์ง€ ๋ชปํ•˜๊ณ  ๋ƒ‰ํผ ์‚ฌ์ดํŠธ์— ์ ‘์†ํ•ด์„œ ์‚ฌ์ „์˜ˆ์•ฝ ๋“ฑ๋ก ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ๋ฒ„๋ ธ๋‹ค.

์ง€๊ธˆ ๋‹น์žฅ ์•„์ดํฐ 12๋ฅผ ์†์— ์ฅ์ง„ ๋ชปํ•˜์ง€๋งŒ ์ถ”ํ›„ ์ •์‹ ํŒ๋งค๊ฐ€ ๊ฐœ์‹œ๋  ๋•Œ ๋‚ด ๋ฉ”์ผ๋กœ ๋ฐ”๋กœ ๊ณต์ง€๋ฅผ ๋ฐ›๊ฒŒ ๋  ๊ฒƒ์ด๊ณ  ๊ตฌ๋งค๋ฅผ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋ˆ„๊ตฐ๊ฐ€๋Š” ์ •์‹ ํŒ๋งค๊ฐ€ ์‹œ์ž‘๋˜๊ณ ์„œ ํ•ด๋‹น ์‚ฌ์ดํŠธ์— ๋“ฑ๋ก๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ์ˆ˜๋„ ์žˆ๋‹ค.

๊ทธ๋•Œ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋ฉ”์ผ๋กœ ๊ณต์ง€๋ฅผ ๋ฐ›๊ฒŒ ๋˜๊ณ  ๊ตฌ๋งค๊ฐ€ ๊ฐ€๋Šฅํ•ด ์งˆ ๊ฒƒ์ด๋‹ค.

์ด๋Ÿฌํ•œ ์ฒ˜๋ฆฌ๋ฅผ (๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ๋ฐฉ์‹) callback ์„ ์“ฐ์ง€ ์•Š๊ณ ! ํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.

โœ๐ŸปPromise is a Javascript object for asynchronous operation.

Promise (ํ”„๋ผ๋ฏธ์Šค) ๋Š” ๋น„๋™๊ธฐ์ ์ธ ๊ฒƒ์„ ์ˆ˜ํ–‰ํ•  ๋•Œ ์ฝœ๋ฐฑ ํ•จ์ˆ˜ ๋Œ€์‹ ์— ์œ ์šฉํ•˜๊ฒŒ ์“ธ ์ˆ˜ ์žˆ๋Š” ์˜ค๋ธŒ์ ํŠธ ์ด๋‹ค.

๐ŸŽ์ด์ œ๋ถ€ํ„ฐ๊ฐ€ ์ค‘์š”ํ•˜๋‹ค!! Promise ์˜ ๋‘ ๊ฐ€์ง€ ํฌ์ธํŠธ!

1. State (์ƒํƒœ)

Process ๊ฐ€ heavy ํ•œ operation ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์ค‘์ธ์ง€ (pending),

์•„๋‹ˆ๋ฉด ๊ธฐ๋Šฅ ์ˆ˜ํ–‰์ด ์™„๋ฃŒ๋˜์–ด์„œ ์„ฑ๊ณตํ–ˆ๋Š”์ง€ (fulfilled),

๊ธฐ๋Šฅ ์ˆ˜ํ–‰์€ ์™„๋ฃŒ๋˜์—ˆ๊ธด ํ–ˆ๋Š”๋ฐ ์‹คํŒจํ–ˆ๋Š”์ง€ (rejected) ์— ๋Œ€ํ•œ ์ƒํƒœ.

์ƒํƒœ ์š”์•ฝ.

  1. ์˜คํผ๋ ˆ์ด์…˜์ด ์ง„ํ–‰ ์ค‘์ผ ๋•Œ : Pending
  2. ์˜คํผ๋ ˆ์ด์…˜์ด ์„ฑ๊ณต์ ์œผ๋กœ ๋๋‚ฌ์„ ๋•Œ (์™„๋ฃŒ) : fulfilled
  3. ์˜คํผ๋ ˆ์ด์…˜ ์ดํ›„ ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†๊ฑฐ๋‚˜ ๋„คํŠธ์›Œํฌ ์˜ค๋ฅ˜ : rejected

2. Producer ์™€ Consumer ์˜ ์ฐจ์ด์ 

  • Producer : ์›ํ•˜๋Š” DATA ๋ฅผ ์ œ๊ณตํ•˜๋Š” ์‚ฌ๋žŒ
  • Consumer : ์ œ๊ณตํ•œ DATA ๋ฅผ ์“ฐ๋Š”, ํ•„์š”๋กœ ํ•˜๋Š” ์‚ฌ๋žŒ

ํ”„๋ผ๋ฏธ์Šค๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ณตํ•˜๋Š” ์—ญํ• ์„ ๋งŒ๋“ค๋ฉด ๋ญํ•˜๋‚˜ (Producer), ๊ฐ–๋‹ค ์จ๋จน์–ด์•ผ ๋ฝ‘๋Š”๊ฒŒ์ง€ (Consumer)..

๐ŸŠ๐Ÿปโ€โ™‚๏ธDeep Dive into Producer

Promise ์ธ์Šคํ„ด์Šค ๊ฐ์ฒด๋ฅผ ์„ ์–ธํ•ด ๋ณด์ž.

const promise = new Promise((resolve, reject) => {
  // doing some heavy work
})

new ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์—ฌ promise ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“œ๋Š”๋ฐ Promise ์˜ ์ธ์ž๋กœ executor ๋ผ๋Š” ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์ „๋‹ฌํ•ด ์ค˜์•ผ ํ•œ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ์œ„์˜ ๋ชจ์–‘์„ ๋ด์„œ ์•Œ๋‹ค์‹œํ”ผ, ์ด executor ์ฝœ๋ฐฑ ํ•จ์ˆ˜์—๋Š” ๋˜ ๋‹ค๋ฅธ 2๊ฐ€์ง€์˜ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์ธ์ž๋กœ ๋ฐ›๋Š”๋‹ค.

resolve ์™€ reject

๊ทธ๊ฒƒ์€ ๋ฐ”๋กœ resolve ์™€ reject ํ‚ค์›Œ๋“œ ์ด๋‹ค.

  • resolve : ๊ธฐ๋Šฅ์„ ์ •์ƒ์ ์œผ๋กœ ์ˆ˜ํ–‰ํ•ด์„œ ๋งˆ์ง€๋ง‰์— ์ตœ์ข… ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ์ฝœ๋ฐฑํ•จ์ˆ˜
  • reject : ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•˜๋‹ค ์ค‘๊ฐ„์— ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๋ฉด ํ˜ธ์ถœํ•˜๊ฒŒ ๋  ์ฝœ๋ฐฑํ•จ์ˆ˜

๊ฐ‘์ž๊ธฐ ๋œฌ๊ธˆ ๋‚˜์˜ค๋Š” ์™œ?

์™œ ์จ? ๋ผ๊ณ  ํ•œ๋‹ค๋ฉด..?

์Œ.. ๋„คํŠธ์›Œํฌ ํ†ต์‹  ์ƒ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๊ฑฐ๋‚˜, ๋Œ€์šฉ๋Ÿ‰ ํŒŒ์ผ์˜ ๋‚ด์šฉ์„ ์ฝ์–ด์˜ฌ ๋•Œ ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋ฆฌ๋ผ๋Š” ๊ฒƒ์€ ์‚ผ์ฒ™ ๋™์ž๋„ ์ง์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋ฆฌํ•˜์—ฌ ์ด๋Ÿฌํ•œ ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆด๋ฒ•ํ•œ task ๋“ค์„ ๋™๊ธฐ์  (synchronous) ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ?

์•„๋งˆ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›๋Š” ๋™์•ˆ ๊ทธ ๋‹ค์Œ ๋ผ์ธ์˜ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜์ง€ ์•Š์„ ๊ฒƒ์ด๋‹ค.

promise ๋ฅผ ๋งŒ๋“œ๋Š” ์ˆœ๊ฐ„?!

const promise = new Promise((resolve, reject) => {
  // doing some heavy work
  console.log('come on you spurs');
})
come on you spurs

promise ๋ฅผ ๋งŒ๋“œ๋Š” ์ˆœ๊ฐ„, ์ „๋‹ฌํ•œ executor ๋ผ๋Š” ์ฝœ๋ฐฑํ•จ์ˆ˜๊ฐ€ ๋ฐ”๋กœ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ์ ์ด ์žˆ๋‹ค.

๋งŒ์•ฝ ๋„คํŠธ์›Œํฌ ์š”์ฒญ์„ ์‚ฌ์šฉ์ž๊ฐ€ ์š”๊ตฌํ–ˆ์„ ๋•Œ๋งŒ ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๋ผ๋ฉด (๊ฐ€๋ น ๋ฒ„ํŠผ์„ ํด๋ฆญํ–ˆ์„ ๋•Œ๋งŒ),

์œ„์ฒ˜๋Ÿผ ์ž‘์„ฑํ•˜๋ฉด ๋ถˆํ•„์š”ํ•œ ๋„คํŠธ์›Œํฌ ํ†ต์‹ ์ด ์ผ์–ด๋‚  ์ˆ˜ ์žˆ๋‹ค.

ํ›—๋‚  ์ด์ ์„ ๊ฐ„๊ณผํ•˜๋‹ค๊ฐ€ ๋ถˆํ•„์š”ํ•œ ๋„คํฌ์›Œํฌ ํ†ต์‹ ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์„ ์•Œ๊ณ  ๋„˜์–ด๊ฐ€์ž.

When new Promise is created,
the executor runs automatically.

์ด์ œ promise ์•ˆ์—์„œ ๋งˆ์น˜ ๋„คํŠธ์›Œํฌ ํ†ต์‹ ์„ ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ, setTimeout ์„ ์ด์šฉํ•ด์„œ ์‹œ๊ฐ„์˜ ๋”œ๋ ˆ์ด๋ฅผ ์ค˜๋ณด์ž,.

promise ์— resolve ๋ฟŒ๋ฆฌ๊ธฐ

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('seolleung2.dev')
  }, 2000)
})

resolve ๋ฅผ ์ผ๋‹ค๋Š” ์˜๋ฏธ๋Š” ์„ฑ๊ณต์ ์œผ๋กœ ๋„คํŠธ์›Œํฌ, ํ˜น์€ ํŒŒ์ผ์—์„œ ์ฝ์–ด์˜จ (๋ฐ›์•„์˜จ) ๊ฒƒ๋“ค์„ ๊ฐ€๊ณตํ•œ ๋ฐ์ดํ„ฐ๋ฅผ resolve ๋ผ๋Š” ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์ „๋‹ฌํ•œ๋‹ค ๋ผ๋Š” ์˜๋ฏธ์ด๋‹ค.

์–ด๋–ค ๊ธฐ๋Šฅ์„ ์„ฑ๊ณต์ ์œผ๋กœ ์ˆ˜ํ–‰ํ–ˆ์„ ๋•Œ, resolve ๋ผ๋Š” ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๊ทธ ๋•Œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜จ ์‚ฌ์šฉ์ž์˜ ์ด๋ฆ„์€ โ€˜seolleung2.devโ€™ ์ด๋‹ค.

๋‹ค์‹œ,

์–ด๋–ค ์ผ์„ 2์ดˆ ์ •๋„ ๋ฌด์–ธ๊ฐ€๋ฅผ ํ•˜๋‹ค๊ฐ€ ๊ฒฐ๊ตญ์—๋Š” ์ผ์„ ์ž˜ ๋งˆ๋ฌด๋ฆฌ ํ•ด์„œ resolve ๋ผ๋Š” ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด์„œ โ€˜seolleung2.devโ€™ ๋ผ๋Š” ๊ฐ’์„ ์ „๋‹ฌํ•ด์ฃผ๋Š” promise ๋ฅผ ๋งŒ๋“ค์—ˆ๋‹ค.

๊ทธ๋Ÿผ ์ด์ œ ๋งŒ๋“  Producer ๋ฅผ ์จ๋จน์–ด ๋ณด๋Š” Consumer ๋ฅผ ์ ์šฉํ•ด ๋ณด์ž.

๐ŸŠ๐Ÿปโ€โ™‚๏ธDeep Dive into Consumer

Consumer ์˜ ์ฒซ๋ฒˆ์งธ ํ‚ค์›Œ๋“œ : then

์ด์ œ ์•ž์„œ ๋งŒ๋“  promise ์—๋‹ค ์›ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ํ•˜๋Š” callback ํ•จ์ˆ˜๋ฅผ ์ „๋‹ฌํ•ด์ฃผ์ž.

promise.then((value) => {
  console.log(value);
})
seolleung2.dev
Promise {<fulfilled>: undefined}
__proto__: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: undefined

์•ž์„œ Producer ์˜ resolve ์ธ์ž๋กœ ํƒœ์šด โ€˜seolleung2.devโ€™ ๊ฐ€ then ์˜ ์ฝœ๋ฐฑ ํ•จ์ˆ˜ ๋‚ด value ๋กœ ๊ฐ’์„ ๋ฐ›๊ฒŒ ๋˜๋ฉด์„œ,

์ฆ‰ Promise ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์ž˜ ์ˆ˜ํ–‰์ด ๋˜์–ด์„œ ๋งˆ์ง€๋ง‰์— ์ตœ์ข…์ ์œผ๋กœ resolve ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด โ€˜seolleung2.devโ€™ ๋ผ๋Š” ๊ฐ’์ด value ๋กœ ๋“ค์–ด์˜จ๋‹ค.

์•„.. ์ •์ƒ์ ์œผ๋กœ ์ˆ˜ํ–‰๋˜์—ˆ์„ ๋•Œ resolve..

๊ทธ๋Ÿผ resolve ๋ง๊ณ  reject ๋ฅผ ์“ฐ๋ฉด ์–ด๋–ป๊ฒŒ ๋˜๋‚˜?

promise ์— reject ๋ฟŒ๋ฆฌ๊ธฐ

Consumer ์˜ ๋‘๋ฒˆ์งธ ํ‚ค์›Œ๋“œ๋ฅผ ๋ธ”๋กœ๊น…ํ•˜๋ ค๋Š” ๋ฐ‘๋ฐฅ์ด๋‹ค.

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject(new Error('No Network'))
  }, 2000)
})

reject ๋ผ๋Š” ํ‚ค์›Œ๋“œ๋กœ ๋ฐ”๊พธ์—ˆ๊ณ  ๊ทธ ์ธ์ž๋กœ๋Š” new Error ๋ผ๊ณ  ํ•ด์„œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ์ œ๊ณตํ•˜๋Š” ์—๋Ÿฌ object ๋ฅผ ๋„ฃ์—ˆ๋‹ค.

๋‚˜์ค‘ ์“ธ ์ผ์ด ์žˆ์„ ๋•Œ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ์ „๋‹ฌํ•ด์•ผ ํ•œ๋‹ค๊ณ  ํ•œ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์ฝ˜์†”๋กœ ์˜ฎ๊ฒจ ์‹คํ–‰ํ•ด ๋ณด๋‹ˆ๊นŒ Uncaught Error ์ฆ‰ ์žกํžˆ์ง€ ์•Š์€ ์—๋Ÿฌ๊ฐ€ ๋œฌ๋‹ค.

reject

์™œ?

์•„๊นŒ then ์ด๋ผ๋Š” ํ‚ค์›Œ๋“œ๋ฅผ ์จ์„œ ์„ฑ๊ณต์ ์œผ๋กœ ์ˆ˜ํ–‰๋˜์—ˆ์„ ๋•Œ์˜ ์ผ€์ด์Šค๋งŒ ๋‹ค๋ฃจ์–ด ๋ณด์•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์ด์ œ ์—๋Ÿฌ ํ•ธ๋“ค๋ง์„ ์œ„ํ•œ ํ‚ค์›Œ๋“œ๋ฅผ ์ตํž ์ฐจ๋ก€๋‹ค.

Consumer ์˜ ๋‘๋ฒˆ์งธ ํ‚ค์›Œ๋“œ : catch

.catch ๋ฅผ ํ†ตํ•ด ๊ทธ ๋‚ด๋ถ€ ์ธ์ž๋กœ error ๋กœ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐ›์•„ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•ด์ค„ ๊ฒƒ์ธ์ง€์— ๋Œ€ํ•œ ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ์‹ค์–ด ๋ณด๋ƒˆ๋‹ค.

promise //
.then((value) => {
  console.log(value);
})
.catch((error) => {
  console.log(error);
})
Error: No Network
    at <anonymous>:3:12
Promise {<fulfilled>: undefined}
__proto__: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: undefined

์ด์ œ ๋” ์ด์ƒ ๋นจ๊ฐ„ ์—๋Ÿฌ๋ฅผ ๋ณด์ด์ง€ ์•Š๊ณ  ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ์ถœ๋ ฅํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

reject2

Consumer ์˜ ์„ธ๋ฒˆ์งธ ํ‚ค์›Œ๋“œ : finally

์ด ํ‚ค์›Œ๋“œ๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฑธ ์•Œ๊ฒŒ ๋˜๋ฉด์„œ ๋ธ”๋กœ๊น…ํ•  ๋•Œ ์ด ์งค์„ ๊ผญ ์“ฐ๊ณ  ์‹ถ์—ˆ๋‹ค.

์—ฌ๊ธฐ๊นŒ์ง€๋งŒ ํ•˜์žโ€ฆ

promise //
  .then(value => {
    console.log(value)
  })
  .catch(error => {
    console.log(error)
  })
  .finally(() => {
    console.log('ํˆ์ด๋‚˜์•Œ๋ฆฌ~')
  })

finally

์ผ์˜ ์ˆ˜ํ–‰ ์„ฑ๊ณต, ์‹คํŒจ์— ์ƒ๊ด€ ์—†์ด ๋ฌด์กฐ๊ฑด ๋งˆ์ง€๋ง‰์— ํ˜ธ์ถœ๋˜์–ด์ง€๋Š” ์•„์ด์ด๋‹ค.

์–ด๋–ค ๊ธฐ๋Šฅ์„ ๋งˆ์ง€๋ง‰์— ์ˆ˜ํ–‰ํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

ํ”„๋กœ๋ฏธ์Šค ์ฒด์ด๋‹์€ ๋‹ค์Œ ๋ธ”๋กœ๊น…์— ์†Œ๊ฐœํ•ด ๋ณด๊ฒ ๋‹ค.


Written by@[DotoriMook]
ํ”„๋ก ํŠธ์—”๋“œ ์ฃผ๋‹ˆ์–ด ๊ฐœ๋ฐœ์ž ๋„ํ† ๋ฆฌ๋ฌต์˜ ๊ธฐ์ˆ ๊ฐœ๋ฐœ ๋ธ”๋กœ๊ทธ ์ž…๋‹ˆ๋‹ค.

GitHubMediumTwitterFacebook