Skip to content

JSDeepDive/CustomPromise

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

30 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

MyPromise

Vanilla Javascript๋กœ Promise ์ง์ ‘ ๊ตฌํ˜„ํ•˜๊ธฐ

  • ์ด ํ”„๋กœ์ ํŠธ์—์„œ๋Š” Javascript Promise ๋™์ž‘ ๋ฐฉ์‹์„ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด, ์ด์™€ ๋™์ผํ•œ ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์ปค์Šคํ…€ ํด๋ž˜์Šค MyPromise๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•ด ๋ณด์•˜๋‹ค.

๋ชฉ์ฐจ

  1. ๋“ค์–ด๊ฐ€๋ฉฐ
  2. Promise๋ž€ ๋Œ€์ฒด ๋ฌด์—‡์ธ๊ฐ€ ๐Ÿง‘๐Ÿปโ€๐Ÿ’ป
  3. Promise ๋‚ด๋ถ€ ๋™์ž‘ ๋ฐฉ์‹ ๐Ÿ—๏ธ
  4. Promise๊ฐ€ ํ•ด๊ฒฐํ•œ ๋ฌธ์ œ ๐Ÿ”ง
  5. Promise์˜ ํ•œ๊ณ„ ๐Ÿ‘ฟ

0. ๋“ค์–ด๊ฐ€๋ฉฐ

  • ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ์—๋Š” ๋ฌด์กฐ๊ฑด async/await ํŒจํ„ด๋งŒ ์‚ฌ์šฉํ•˜๋‹ค๊ฐ€, Javascript์˜ ๋Œ€ํ‘œ์  ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ๋ฐฉ์‹์ธ (1) ์ฝœ๋ฐฑ ํŒจํ„ด (2) Promise ํŒจํ„ด (3) async/await ํŒจํ„ด ๊ฐ๊ฐ์˜ ์žฅ๋‹จ์ ์„ ์•Œ๊ณ  ์จ์•ผํ•˜์ง€ ์•Š์„๊นŒํ•˜๋Š” ์ƒ๊ฐ์ด ๋ถˆํ˜„๋“ฏ ๋“ค์—ˆ๋‹ค. (์ด ๊ฐ•์„ ๊ฑด๋„ˆ์ง€ ๋ง์•˜์–ด์•ผ ํ–ˆ๋‹คโ€ฆ)
  • ์‹œ์ค‘์˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ž์Šต์„œ, ์œ ๋ช… ๋ธ”๋กœ๊ทธ ํฌ์ŠคํŠธ๋ฅผ ๋’ค์ ธ๊ฐ€๋ฉฐ ๊ฐ ํŒจํ„ด์˜ ์žฅ๋‹จ์ ์„ ํ…์ŠคํŠธ ํ˜•ํƒœ๋กœ ํ•™์Šตํ–ˆ์ง€๋งŒ, ์ฝ”๋“œ๋กœ ์˜ฎ๊ธฐ์งˆ ์•Š์œผ๋‹ˆ ๋„ํ†ต ์™€๋‹ฟ์ง€ ์•Š๋Š”๋‹ค.
  • ์ง์ ‘ Promise๋ฅผ ๊ตฌํ˜„ํ•ด๋ณด๋ฉด, ์ฝœ๋ฐฑ ํŒจํ„ด์˜ ํ•œ๊ณ„๋ฅผ Promise๊ฐ€ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ•˜๋ ค ํ–ˆ๋Š”์ง€ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์ง€ ์•Š์„๊นŒ?๋ผ๋Š” ๋‹จ์ดํ•œ ์ƒ๊ฐ์—์„œ ์ถœ๋ฐœํ•œ ํ”„๋กœ์ ํŠธ๋ฅผ ์†Œ๊ฐœํ•œ๋‹ค.

1. Promise๋ž€ ๋Œ€์ฒด ๋ฌด์—‡์ธ๊ฐ€ ๐Ÿง‘๐Ÿปโ€๐Ÿ’ป

  • ํ•˜๋‹จ์€ Promise๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•œ custom Promise์ธ MyPromise ์„ธ๋ถ€ ์ฝ”๋“œ์— ๋Œ€ํ•œ ์„ค๋ช…์ด๋‹ค. ์ดํ•ด๊ฐ€ ๋˜์ง€ ์•Š๋Š” ๋ถ€๋ถ„์ด ์žˆ๋‹ค๋ฉด ํŽผ์ณ ์„ธ๋ถ€ ๊ตฌํ˜„ ํ™•์ธํ•ด๋ณด์ž.

โœ… Promise๋Š” state, result, ์ฝœ๋ฐฑ ํ•จ์ˆ˜ ๋ฐฐ์—ด๋“ค์„ ์ƒํƒœ๊ฐ’์œผ๋กœ ๊ฐ–๋Š” ๊ฐ์ฒด์ด๋‹ค.

[๐Ÿ”Javascript Promise ๊ตฌํ˜„ ๋ฐฉ์‹์„ ์‚ดํŽด๋ณด์ž]

- custom Promise์ธ MyPromise๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ์ „์— ์šฐ์„  Javascript์—์„œ Promise๊ฐ€ ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„๋˜์–ด ์žˆ๋Š”์ง€ ์‚ดํŽด๋ณด์ž. - Javascript์—์„œ๋Š” `new` ํ‚ค์›Œ๋“œ์™€ ํ•จ๊ป˜ `Promise ์ƒ์„ฑ์ž ํ•จ์ˆ˜`๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ `Promise ๊ฐ์ฒด`๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. ```javascript const promise = new Promise((resolve, reject) => { const value = 'value' if( /* ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ์„ฑ๊ณต ์‹œ */) { resolve(value) } else { /* ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ์‹คํŒจ ์‹œ */ reject(value) } }) ```
  • ์ด๋ ‡๊ฒŒ ์ƒ์„ฑ๋œ promise ๊ฐ์ฒด๋Š” [[PromiseState]]์™€ [[PromiseResult]] ์ƒํƒœ๊ฐ’์„ ๊ฐ€์ง„๋‹ค.
  • ์ด ์™ธ์—๋„ ๊ฐ์ฒด์—๋Š” ๋น„๋™๊ธฐ ํ›„์†์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ๋ฉ”์„œ๋“œ์ธ then, catch, finally๊ฐ€ ํฌํ•จ๋œ๋‹ค. Promise ๊ตฌ์„ฑ

[๐Ÿง‘๐Ÿปโ€๐Ÿ’ปย MyPromise์— mocking ํ•ด๋ณด์ž]

- ํด๋ž˜์Šค ๋ฌธ๋ฒ•์œผ๋กœ ์ง์ ‘ MyPromise๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•ด๋ณด์ž. Promise๋Š” `๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ์ƒํƒœ(state)`์™€ `์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ(result)`๋ฅผ ๊ฐ–๋Š” ๊ฐ์ฒด๋กœ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. - ๋น„๋™๊ธฐ ํ›„์†์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ์ธ `then`, `catch`, `finally`๋ฅผ ํ†ตํ•ด ๋“ฑ๋กํ•œ ์ฝœ๋ฐฑํ•จ์ˆ˜๋“ค์€ MyPromise ๋‚ด์—์„œ ๋ฐฐ์—ด ํ˜•ํƒœ๋กœ ๊ด€๋ฆฌํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค. ```javascript const STATE = { PENDING: "pending", FULFILLED: "fulfilled", REJECTED: "rejected", }
class MyPromise {
  #state = STATE.PENDING
  #result
    #thenCbs = []
  #catchCbs = []
  #finallyCbs = []

  constructor(cb) {
    try {
      cb(this.#onFulfilled, this.#onRejected)
    } catch (e) {
      this.#onRejected(e)
    }

  #onFulfilled(result) {...} // promise์˜ resolve ํ•จ์ˆ˜
  #onRejected(result) {...}  // promise์˜ reject ํ•จ์ˆ˜
}
```

โœ…ย Promise ํ›„์† ์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ๋Š” ์ฝœ๋ฐฑํ•จ์ˆ˜ ๋ฐฐ์—ด์— ์ธ์ž๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.

[๐Ÿ”Javascript Promise ๊ตฌํ˜„ ๋ฐฉ์‹์„ ์‚ดํŽด๋ณด์ž]

- Javascript์—์„œ๋Š” `then`, `catch`, `finally` ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ๋น„๋™๊ธฐ ํ›„์†์ฒ˜๋ฆฌ์™€ ๊ด€๋ จ๋œ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋“ค์„ `Promise` ๊ฐ์ฒด์— ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ๋‹ค. - `then`์€ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๊ฐ€ ์„ฑ๊ณตํ–ˆ์„ ๋•Œ ํ˜ธ์ถœ ํ•  ์„ฑ๊ณต ์ฒ˜๋ฆฌ ์ฝœ๋ฐฑ ํ•จ์ˆ˜์ธ `onFulfilled`์™€ ์‹คํŒจ ์‹œ ํ˜ธ์ถœํ•  ์‹คํŒจ ์ฒ˜๋ฆฌ ์ฝœ๋ฐฑํ•จ์ˆ˜์ธ `onRejected`๋ฅผ ์ธ์ž๋กœ ๋ฐ›๋Š”๋‹ค. - `catch`๋Š” ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ์‹คํŒจ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋งŒ์„ ์ธ์ž๋กœ ๋ฐ›๋Š”๋‹ค. ์ฝœ๋ฐฑ ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ ์‹คํŒจ ์›์ธ์— ๋Œ€ํ•œ ๊ฐ’์„ ๋ฐ›๋Š”๋‹ค. - `finally`๋Š” ๋น„๋™๊ธฐ ์„ฑ๊ณต, ์ฒ˜๋ฆฌ ์‹คํŒจ ์—ฌ๋ถ€์™€ ๊ด€๊ณ„ ์—†์ด ์‹คํ–‰ํ•  ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์ธ์ž๋กœ ๋ฐ›๋Š”๋‹ค. ์ฝœ๋ฐฑ ํ•จ์ˆ˜์—์„œ๋Š” ๋ณ„๋„์˜ ์ธ์ž๋ฅผ ๋ฐ›์ง€ ์•Š๋Š”๋‹ค.
```javascript
then(onFulfilled)
then(onFulfilled, onRejected)
then(
  (result) => { /* fulfillment handler */ },
  (reason) => { /* rejection handler */ },
)

catch(onRejected)
catch((reason) => {
  // rejection handler
})

finally(onFinally)
finally(() => {
  // Code that will run after promise is settled (fulfilled or rejected)
})
```

[๐Ÿง‘๐Ÿปโ€๐Ÿ’ปย MyPromise์— mocking ํ•ด๋ณด์ž]

- MyPromise์— `then`, `catch`, `finally` ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•ด๋ณด์ž. - `then` ๋ฉ”์„œ๋“œ๋Š” `promise ์„ฑ๊ณต, ์‹คํŒจ ์‹œ์˜ ์ฝœ๋ฐฑ ํ•จ์ˆ˜` ๋‘˜ ๋ชจ๋‘๋‚˜ ๋‘˜ ์ค‘ ํ•˜๋‚˜๋งŒ์„ ๋ฐ›์„ ์ˆ˜๋„ ์žˆ์œผ๋ฏ€๋กœ `undefined` ์กฐ๊ฑด๋ฌธ์„ ์ถ”๊ฐ€ํ•ด ์ฒ˜๋ฆฌํ•œ๋‹ค. - `catch(cb)` ๋ฉ”์„œ๋“œ๋Š” `then(undefined, cb)`์™€ ๋™์ผํ•˜๋ฏ€๋กœ ์ด๋กœ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ๋‹ค. - `finally(cb)` ๋ฉ”์„œ๋“œ๋Š” ์ธ์ž๋ฅผ ์ „๋‹ฌ๋ฐ›์ง€ ์•Š๊ณ  ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ์ˆ˜ํ–‰ํ•˜๋˜, `result`๋Š” ์ „๋‹ฌํ•ด ์ฃผ์–ด์•ผ ํ•˜๋ฏ€๋กœ ์•„๋ž˜์™€ ๊ฐ™์€ ํ˜•ํƒœ๋กœ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.
    ```javascript
    class MyPromise {
    	...
      #thenCbs = []
      #catchCbs = []
    
    	then(thenCb, catchCb) {
    		if (thenCb != undefined) this.#thenCbs.push(thenCb);
        if (catchCb != undefined) this.#catchCbs.push(catchCb);
      }
    
    	catch(cb) {
        this.then(undefined, cb)
      }
    	
    	finally(cb) {
    		this.then(
          (result) => {
            cb()
            return result
          },
          (result) => {
            cb()
            throw result
          }
        )
    	}
    }
    ```

โœ…ย resolve, reject ํ˜ธ์ถœ๋กœ Promise ์ƒํƒœ๊ฐ€ ๋ณ€ํ™”ํ•˜๋ฉด, ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ์ธ์ž๋กœ ์ฝœ๋ฐฑ ํ•จ์ˆ˜ ๋ฐฐ์—ด์ด ํ˜ธ์ถœ๋œ๋‹ค.

[๐Ÿ”Javascript Promise ๊ตฌํ˜„ ๋ฐฉ์‹์„ ์‚ดํŽด๋ณด์ž]

  • Javascript์—์„œ๋Š” Promise ์„ฑ๊ณต์‹œ resolve, ์‹คํŒจ์‹œ reject ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

      ```javascript
      const promise = new Promise((resolve, reject) => {
      	const value = 'value'
      	if(	/* ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ์„ฑ๊ณต ์‹œ */) {
      	  resolve(value)
      	}
        else { /* ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ์‹คํŒจ ์‹œ */
          reject(value) 
        }
      })
      ```
    
  • resolve ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด, Promise ์ƒํƒœ๊ฐ€ fulfilled๋กœ ๋ณ€๊ฒฝ๋œ๋‹ค. ์ดํ›„, then(onFulfilled) ๋ฉ”์„œ๋“œ์— ์˜ํ•ด ๋“ฑ๋ก๋œ onFulfilled ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋“ค์ด ๋“ฑ๋ก ์ˆœ์„œ๋Œ€๋กœ ์ˆ˜ํ–‰๋œ๋‹ค. ์ด ๋•Œ, Promise ๊ฒฐ๊ณผ๊ฐ’์ด onFulfilled(result) ์ธ์ž๋กœ ์‚ฌ์šฉ๋œ๋‹ค.

  • resolve ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด, Promise ์ƒํƒœ๊ฐ€ rejected๋กœ ๋ณ€๊ฒฝ๋œ๋‹ค. ์ดํ›„, then(onFulfilled, onRejected) ๋ฉ”์„œ๋“œ์— ์˜ํ•ด ๋“ฑ๋ก๋œ onRejected ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋“ค์ด ๋“ฑ๋ก ์ˆœ์„œ๋Œ€๋กœ ์ˆ˜ํ–‰๋œ๋‹ค. ์ด ๋•Œ, Promise ๊ฒฐ๊ณผ๊ฐ’์ด onRejected(result) ์ธ์ž๋กœ ์‚ฌ์šฉ๋œ๋‹ค.

[๐Ÿง‘๐Ÿปโ€๐Ÿ’ปย MyPromise์— mocking ํ•ด๋ณด์ž]

- promise ์„ฑ๊ณต, ์‹คํŒจ์‹œ ํ˜ธ์ถœ๋˜๋Š” `resolve`, `reject` ํ•จ์ˆ˜๋ฅผ `onResolved`, `onRejected` ํ•จ์ˆ˜๋กœ ๊ตฌํ˜„ํ•˜์˜€๋‹ค. - ํ›„์† ์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ์ธ `then`, `catch`๋ฅผ ํ†ตํ•ด ๋“ฑ๋ก๋œ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋“ค์€ `MyPromise`์˜ `thenCbs`, `catchCbs` ๋ฐฐ์—ด์— ์ €์žฅ๋˜์–ด MyPromise์˜ `onFulfilled`, `onRejected` ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ ๋  ๋•Œ forEach ๋ฌธ์— ์˜ํ•ด ์‹คํ–‰๋œ๋‹ค. - ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ๋Š” ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ์ƒํƒœ์™€ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ๋ณ€๊ฒฝํ•œ๋‹ค. ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ์ƒํƒœ๊ฐ’์— ๋”ฐ๋ผ ์„ ํƒ์ ์œผ๋กœ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋ถ€๋ถ„์„ `runCallbacks` ํ•จ์ˆ˜๋กœ ๋ถ„๋ฆฌํ•˜์˜€๋‹ค.
```javascript
class MyPromise {
  ...
  #thenCbs = []
  #catchCbs = []

	#runCallbacks() {
    if (this.#state === STATE.FULFILLED) {
      this.#thenCbs.forEach((callback) => {
        callback(this.#result)
      })

	      this.#thenCbs = [] // ์—ฌ๋Ÿฌ then ๋‚ด thenCbs ์žฌํ˜ธ์ถœ ๋ฐฉ์ง€
    }

    if (this.#state === STATE.REJECTED) {
      this.#catchCbs.forEach((callback) => {
        callback(this.#result)
      })

      this.#catchCbs = [] // ์—ฌ๋Ÿฌ then ๋‚ด catchCbs ์žฌํ˜ธ์ถœ ๋ฐฉ์ง€
    }
  }

  #onFulfilled(result) {
      if (this.#state !== STATE.PENDING) return // ๋™์ผ then ๋‚ด resolve ์žฌํ˜ธ์ถœ ๋ฐฉ์ง€

      this.#result = result
      this.#state = STATE.FULFILLED
      this.#runCallbacks()
  }

  #onRejected(result) {
      if (this.#state !== STATE.PENDING) return // ๋™์ผ then ๋‚ด reject ์žฌํ˜ธ์ถœ ๋ฐฉ์ง€

      this.#result = result
      this.#state = STATE.REJECTED
      this.#runCallbacks()
  }
}
```

โœ…ย Promise ํ›„์†์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ๋Š” ํ•ญ์ƒ Promise๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— Promise ๋ฉ”์„œ๋“œ ์ฒด์ด๋‹์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

[๐Ÿ”Javascript Promise ๊ตฌํ˜„ ๋ฐฉ์‹์„ ์‚ดํŽด๋ณด์ž]

  • Javascript์—์„œ promise ํ›„์†์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ์ธ then, catch, finally๋Š” ์–ธ์ œ๋‚˜ ์ƒˆ๋กœ์šด promise๋ฅผ ์ƒ์„ฑํ•ด ๋ฐ˜ํ™˜ํ•ด์ค€๋‹ค. ์ด์ฒ˜๋Ÿผ ํ›„์†์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ๊ฐ€ ํ•ญ์ƒ promise๋ฅผ ๋ฐ˜ํ™˜๋œ๋‹ค๋Š” ์•ฝ์†์„ ์ง€ํ‚ค๊ธฐ ๋•Œ๋ฌธ์—, ๊ฐœ๋ฐœ์ž๋Š” promise ํ›„์† ์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ๋“ค์„ ์ฒด์ด๋‹ํ•ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ํ›„์† ์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ์˜ ์ฝœ๋ฐฑํ•จ์ˆ˜๊ฐ€ (1) promise๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒฝ์šฐ, ํ•ด๋‹น promise๋ฅผ ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
    • ๋ฐ˜๋ฉด, (2) ์ฝœ๋ฐฑํ•จ์ˆ˜๊ฐ€ promise๊ฐ€ ์•„๋‹Œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋ฉด, ํ•ด๋‹น๊ฐ’์„ resolve ๋˜๋Š” reject ํ•จ์ˆ˜๋กœ ๊ฐ์‹ธ์ฃผ๋ฉด promise ํ˜•ํƒœ๋กœ ๋ฐ˜ํ™˜๋œ๋‹ค.

[๐Ÿง‘๐Ÿปโ€๐Ÿ’ปย MyPromise์— mocking ํ•ด๋ณด์ž]

  • ์•ž์„œ ๋งŒ๋“  MyPromise์˜ then, catch, finally ๋ฉ”์„œ๋“œ๊ฐ€ ํ•ญ์ƒ promise๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ๋ณ€๊ฒฝํ•ด์ฃผ์ž.

  • ์šฐ์„ , ๋ฉ”์„œ๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ธฐ ์ „์— MyPromise์˜ onFulfilled์™€ onRejected๋ฅผ ์ƒ์„ฑ์ž ํ•จ์ˆ˜์ธ MyPromise์˜ this์— ๋ฐ”์ธ๋”ฉํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

    class MyPromise {
      #thenCbs = []
      #catchCbs = []
      #state = STATE.PENDING
      #result
    
      // promise chaining์„ ์œ„ํ•ด this ๋ฐ”์ธ๋”ฉ ์ˆ˜ํ–‰
      #onFulfilledBind = this.#onFulfilled.bind(this)
      #onRejectedBind = this.#onRejected.bind(this)
    
      constructor(cb) {
        try {
          cb(this.#onFulfilledBind, this.#onRejectedBind)
        } catch (e) {
          this.#onRejected(e)
        }
      }
    }
  • then ๋ฉ”์„œ๋“œ์—์„œ MyPromise ์ƒ์„ฑ์ž ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ๊ทธ ๊ฒฐ๊ณผ ์ƒ์„ฑ๋œ MyPromise ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ์ˆ˜์ •ํ•ด๋ณด์ž.

    • thenCbs์™€ catchCbs ๋ฐฐ์—ด์— ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ์ฝ”๋“œ๋„ resolve, reject ํ•จ์ˆ˜๋กœ ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ wrapping ํ•ด์ค€๋‹ค.
    • ์ด ๋•Œ, then ๋ฉ”์„œ๋“œ์—์„œ ์ธ์ž๋ฅผ ํ•˜๋‚˜๋งŒ ๋ฐ›๋Š” ๊ฒฝ์šฐ๋ฅผ ๋Œ€๋น„ํ•˜์—ฌ, undefined์— ๋”ฐ๋ฅธ ๋ถ„๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ฃผ์–ด์•ผ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.
    class MyPromise {
        ...
    
        then(thenCb, catchCb) {
            return new MyPromise((resolve, reject) => {
              this.#thenCbs.push((result) => {
                if (thenCb == undefined) { // then(undefined, catchCb) ์ฒ˜๋ฆฌ
                  resolve(result)
                  return
                }
    
                try {
                  resolve(thenCb(result)) 
                } catch (e) {
                  reject(e)            // then ๋‚ด๋ถ€์—์„œ ์—๋Ÿฌ๊ฐ€ ์žˆ์œผ๋ฉด ๋ฐ”๋กœ rejected ์ƒํƒœ๋กœ ๋ณ€๊ฒฝ๋จ.
                }
              })
    
              this.#catchCbs.push((result) => {
                if (catchCb == undefined) { // then(thenCb) ์ฒ˜๋ฆฌ
                  reject(result)
                  return
                }
    
                try {
                  resolve(catchCb(result)) 
                } catch (e) {
                  reject(e)
                }
              })
            })
          }
        }
    }
  • catch ๋ฉ”์„œ๋“œ์™€ finally ๋ฉ”์„œ๋“œ๋Š” return ๋ฌธ๋งŒ ์ถ”๊ฐ€ํ•˜์—ฌ promise๋ฅผ ๋ฆฌํ„ดํ•˜๋„๋ก ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

    class MyPromise {
        ...
        catch(cb) {
        return this.then(undefined, cb)
      }
    
        finally(cb) {
        return this.then(
          (result) => {
            cb()
            return result
          },
          (result) => {
            cb()
            throw result
          }
        )
      }
    }
  • ์ด์™€ ๊ฐ™์€ ํ˜•ํƒœ๋กœ MyPromise์˜ ๋น„๋™๊ธฐ ํ›„์† ์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ์ธ then, catch , finally ๊ฐ€ ๋ชจ๋‘ MyPromise๋ฅผ ๋ฆฌํ„ดํ•˜๊ฒŒ ํ•ด์ฃผ๋ฉด Promise ์ฒด์ด๋‹ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ๋ชจ๋‘ ํ†ต๊ณผํ•  ์ˆ˜ ์žˆ๋‹ค.

    ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ

โœ… Promise ํ›„์†์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ์˜ ์ฝœ๋ฐฑํ•จ์ˆ˜๋Š” microtask queue์— ๋“ฑ๋ก๋œ๋‹ค.

[๐Ÿ”Javascript Promise ๊ตฌํ˜„ ๋ฐฉ์‹์„ ์‚ดํŽด๋ณด์ž]

  • Javascript์—์„œ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด Promise ๋‚ด๋ถ€์— ๋“ฑ๋ก๋œ ์ฝœ๋ฐฑํ•จ์ˆ˜๋“ค์€ microtask queue์— ๋“ค์–ด๊ฐ€ ์ฐจ๋ก€๋ฅผ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.

    image

  • ์ดํ›„ Javascript Event loop์— ์˜ํ•ด ์ฝœ์Šคํƒ์ด ๋น„์–ด์žˆ๋Š” ๊ฒฝ์šฐ, microtask queue์— ๋Œ€๊ธฐ์ค‘์ธ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋“ค์ด call stack์œผ๋กœ ์ด๋™๋˜์–ด ์‹คํ–‰๋œ๋‹ค.

    • microtask queue์˜ ์šฐ์„ ์ˆœ์œ„๋Š” event queue(= callback queue, task queue)์˜ ์šฐ์„ ์ˆœ์œ„๋ณด๋‹ค ๋†’๋‹ค.

[๐Ÿง‘๐Ÿปโ€๐Ÿ’ปย MyPromise์— mocking ํ•ด๋ณด์ž]

  • ์ง€๊ธˆ๊นŒ์ง€๋Š” ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ์— ๋Œ€ํ•œ ๊ณ ๋ ค ์—†์ด MyPromise ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์˜€๋‹ค.

  • ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ์ฝ”๋“œ๊ฐ€ ์„ฑ๊ณตํ•˜์—ฌ Javascript์˜ Promise์—์„œ resolve, reject๋ฅผ ํ˜ธ์ถœํ•˜์˜€์„ ๋•Œ, microtask queue์— ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋“ค์ด ๋“ฑ๋ก๋˜๋Š” ๊ณผ์ •์„ mocking ํ•ด๋ณด์ž.

  • ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋“ค์„ ์‹ค์ œ ์‹คํ–‰ํ•˜๋Š” runCallbacks ํ•จ์ˆ˜ ๋‚ด๋ถ€ ์ฝ”๋“œ๋ฅผ queueMicrotask() ํ•จ์ˆ˜๋กœ ๊ฐ์‹ธ์ฃผ๋ฉด ๊ฐ„๋‹จํ•˜๊ฒŒ microtask queue์— ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋“ค์„ ๋“ฑ๋กํ•ด์ค„ ์ˆ˜ ์žˆ๋‹ค.

    #runCallbacks() {
        queueMicrotask(() => {
          if (this.#state === STATE.FULFILLED) {
            this.#thenCbs.forEach((callback) => {
              callback(this.#result)
            })
    
            this.#thenCbs = [] // ์—ฌ๋Ÿฌ then ๋‚ด thenCbs ์žฌํ˜ธ์ถœ ๋ฐฉ์ง€
          }
    
          if (this.#state === STATE.REJECTED) {
            this.#catchCbs.forEach((callback) => {
              callback(this.#result)
            })
    
            this.#catchCbs = [] // ์—ฌ๋Ÿฌ then ๋‚ด catchCbs ์žฌํ˜ธ์ถœ ๋ฐฉ์ง€
          }
    
          if (this.#state !== STATE.PENDING) {
            this.#finallyCbs.forEach((callback) => {
              callback()
            })
    
            this.#finallyCbs = []
          }
        })
      }

โœ…ย Promise๋Š” ์ด ์™ธ์—๋„ ๋‹ค์–‘ํ•œ static method๋“ค์„ ์ œ๊ณตํ•˜์—ฌ ๊ฐ„๋‹จํžˆ ๋น„๋™๊ธฐ ํ›„์† ์ฒ˜๋ฆฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ค€๋‹ค.

[๐Ÿ”Javascript Promise ๊ตฌํ˜„ ๋ฐฉ์‹์„ ์‚ดํŽด๋ณด์ž]

  • Javascript Promise์„ ์ฝœ๋ฐฑ ํŒจํ„ด์˜ syntactic sugar + alpha ๋ผ๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ๊ธฐ์กด ์ฝœ๋ฐฑ ํŒจํ„ด์—์„œ ์ง€์›ํ•˜์ง€ ์•Š๋˜ ๋น„๋™๊ธฐ ์ฝ”๋“œ ํ›„์† ์ฒ˜๋ฆฌ์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํŽธ๋ฆฌํ•œ static methods๋ฅผ ์ง€์›ํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

    static method ๊ธฐ๋Šฅ
    Promise.resolve(value) {state: fulfilled, result: value} ํ˜•ํƒœ์˜ Promise ๊ฐ์ฒด ๋ฐ˜ํ™˜
    Promise.reject(value) {state: rejected, result: value} ํ˜•ํƒœ์˜ Promise ๊ฐ์ฒด ๋ฐ˜ํ™˜
    Promise.all(Iterable) Promise๋ฅผ ์š”์†Œ๋กœ ๊ฐ–๋Š” ๋ฐฐ์—ด์„ ์ธ์ž๋กœ ๋ฐ›์Œ. (1) Promise ๋ฐฐ์—ด ๋‚ด์˜ Promise๊ฐ€ ๋ชจ๋‘ fulfilled๋˜๊ฑฐ๋‚˜ (2) ๊ทธ ์ค‘ ํ•˜๋‚˜๋ผ๋„ rejected ๋œ ๊ฒฝ์šฐ ํ•จ์ˆ˜๋ฅผ ์ข…๋ฃŒํ•˜๊ณ , ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ๋ฐฐ์—ด์— ๋‹ด์•„ ๋ฐ˜ํ™˜
    Promise.allSettled(Iterable) Promise๋ฅผ ์š”์†Œ๋กœ ๊ฐ–๋Š” ๋ฐฐ์—ด์„ ์ธ์ž๋กœ ๋ฐ›์Œ. Promise ๋ฐฐ์—ด ๋‚ด์˜ Promise๊ฐ€ ๋ชจ๋‘ settled ๋˜๋ฉด ํ•จ์ˆ˜๋ฅผ ์ข…๋ฃŒํ•˜๊ณ , ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ๋ฐฐ์—ด์— ๋‹ด์•„ ๋ฐ˜ํ™˜.
    Promise.race(Iterable) Promise๋ฅผ ์š”์†Œ๋กœ ๊ฐ–๋Š” ๋ฐฐ์—ด์„ ์ธ์ž๋กœ ๋ฐ›์Œ. Promise ๋ฐฐ์—ด ๋‚ด์˜ Promise ์ค‘ ํ•˜๋‚˜๋ผ๊ณ  settled ๋˜๋ฉด ํ•จ์ˆ˜ ์ข…๋ฃŒํ•จ. ๊ฐ€์žฅ ๋จผ์ € settled๊ฐ€ ๋œ Promise๋งŒ ๋ฐ˜ํ™˜.
    Promise.any(Iterable) Promise๋ฅผ ์š”์†Œ๋กœ ๊ฐ–๋Š” ๋ฐฐ์—ด์„ ์ธ์ž๋กœ ๋ฐ›์Œ. (1) Promise ๋ฐฐ์—ด ๋‚ด์˜ Promise๊ฐ€ ๋ชจ๋‘ rejected ๋˜๊ฑฐ๋‚˜ (2) ๊ทธ ์ค‘ ํ•˜๋‚˜๋ผ๋„ fulfilled ๋œ ๊ฒฝ์šฐ ํ•จ์ˆ˜๋ฅผ ์ข…๋ฃŒํ•˜๊ณ , ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ๋ฐฐ์—ด์— ๋‹ด์•„ ๋ฐ˜ํ™˜

[๐Ÿง‘๐Ÿปโ€๐Ÿ’ปย MyPromise์— mocking ํ•ด๋ณด์ž]

  • MyPromise์—๋„ static methods๋ฅผ ์ถ”๊ฐ€ํ•ด๋ณด์ž.
    • resolve, reject๋Š” Promise๋ฅผ ์ฐจ์šฉํ•ด ๊ฐ„๋žตํžˆ ๊ตฌํ˜„ํ•˜์ž.

      class MyPromise {
          ...
          static resolve(result) {
          return new Promise((resolve) => {
            resolve(result)
          })
        }
      
        static reject(result) {
          return new Promise((resolve, reject) => {
            reject(result)
          })
        }
      }
    • all ๋ฉ”์„œ๋“œ์—์„œ๋Š” ๊ฐ Promise๊ฐ€ fulfilled ๋  ๋•Œ๋งˆ๋‹ค completedPromises์˜ ์ˆ˜์™€ ๋น„๊ตํ•˜์—ฌ, promises ๋ฐฐ์—ด์ด ๋ชจ๋‘ ์ˆ˜ํ–‰๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ด์ค€๋‹ค. ๋งŒ์•ฝ, ํ•˜๋‚˜๋ผ๋„ reject๋œ ๊ฒฝ์šฐ, ๋ฐ”๋กœ ์ข…๋ฃŒํ•  ์ˆ˜ ์žˆ๋„๋ก, catch ๋ฉ”์„œ๋“œ์— reject๋ฅผ ๋“ฑ๋กํ•ด์ค€๋‹ค.

      class MyPromise {
          ...
          static all(promises) {
          const results = []
          let completedPromises = 0
      
          return new MyPromise((resolve, reject) => {
            for (let i = 0; i < promises.length; i++) {
              const promise = promises[i]
              promise
                .then((result) => {
                  completedPromises++
                  results[i] = result
                  // ๋ชจ๋“  promise ๊ฒฐ๊ณผ๊ฐ’์ด ๋‚˜์˜ค๋ฉด ์ˆ˜ํ–‰
                  if (completedPromises === promises.length) {
                    resolve(results)
                  }
                })
                .catch(reject)
            }
          })
        }
      }
    • allSettled ๋ฉ”์„œ๋“œ์—์„œ๋Š” ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ ๋ฐฐ์—ด์˜ ๋‚ด๋ถ€ Promise๊ฐ€ onFulfilled์˜ ๊ฒฝ์šฐ, {status, result}, onRejected ๋œ ๊ฒฝ์šฐ {status, reason} ํ˜•ํƒœ์—ฌ์•ผํ•จ์— ์œ ์˜ํ•ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค.

      class MyPromise {
          ...
          static allSettled(promises) {
          const results = []
          let completedPromises = 0
      
          return new MyPromise((resolve, reject) => {
            for (let i = 0; i < promises.length; i++) {
              const promise = promises[i]
              promise
                .then((result) => {
                  results[i] = { status: STATE.FULFILLED, result }
                })
                .catch((reason) => {
                  results[i] = { status: STATE.REJECTED, reason }
                })
                .finally(() => {
                  completedPromises++
                  if (completedPromises === promises.length) {
                    resolve(results)
                  }
                })
            }
          })
        }
      }
    • race ๋ฉ”์„œ๋“œ๋Š” ๊ฐ€์žฅ ๋จผ์ € ์ฒ˜๋ฆฌ๋œ Promise๋งŒ ๋ฐ˜ํ™˜๋จ์— ์œ ์˜ํ•ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค.

      class MyPromise {
          ...
          static race(promises) {
          return new MyPromise((resolve, reject) => {
            promises.forEach((promise) => {
              promise.then(resolve).catch(reject)
            })
          })
        }
      }
    • any ๋ฉ”์„œ๋“œ๋Š” all ๋ฉ”์„œ๋“œ์™€ ๋ฐ˜๋Œ€๋กœ ๋™์ž‘ํ•œ๋‹ค.

      class MyPromise {
          ...
          static any(promises) {
          const errors = []
          let rejectedPromises = 0
      
          return new MyPromise((resolve, reject) => {
            for (let i = 0; i < promises.length; i++) {
              const promise = promises[i]
              promise.then(resolve).catch((result) => {
                rejectedPromises++
                errors[i] = result
                // ๋ชจ๋“  promise ๊ฒฐ๊ณผ๊ฐ’์ด ๋‚˜์˜ค๋ฉด ์ˆ˜ํ–‰
                if (rejectedPromises === promises.length) {
                  reject(new AggregateError(errors, "ALl promises were rejected"))
                }
              })
            }
          })
        }
      }
    • ์œ„์™€ ๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด, static method์— ๋Œ€ํ•œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ๋˜ํ•œ ๋ชจ๋‘ ํ†ต๊ณผํ•  ์ˆ˜ ์žˆ๋‹ค. ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ

2. Promise ๋‚ด๋ถ€ ๋™์ž‘ ๋ฐฉ์‹ ๐Ÿ—๏ธ

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

๐Ÿ’ก Promise = ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด state, result, ์—ฌ๋Ÿฌ callback ๋ฐฐ์—ด์„ ๊ด€๋ฆฌํ•˜๋Š” ๊ฐ์ฒด

  1. Promise ํ›„์† ์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ then, catch, finally๋ฅผ ํ†ตํ•ด ๋“ฑ๋กํ•œ ์ฝœ๋ฐฑํ•จ์ˆ˜๋Š” Promise ๋‚ด๋ถ€์— ๋ฐฐ์—ด ํ˜•ํƒœ๋กœ ์ €์žฅ๋˜๊ณ , Promise state๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ํ•ด๋‹น ์ƒํƒœ์— ๋”ฐ๋ผ ์„ ํƒ์ ์œผ๋กœ forEach๋ฌธ์„ ํ†ตํ•ด callback ๋ฐฐ์—ด์„ ์ˆ˜ํ–‰ํ•œ๋‹ค. ๊ฐ ์ฝœ๋ฐฑ์˜ ์ธ์ž๋กœ result๊ฐ€ ๋“ค์–ด๊ฐ„๋‹ค. ์ด ๋•Œ, ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋“ค์€ microtask queue์— ๋“ฑ๋ก๋œ๋‹ค.

  2. Promise ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด, ํ›„์† ์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ๋Š” ๋ชจ๋‘ Promise๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ๋•๋ถ„์— ๊ฐœ๋ฐœ์ž๋Š” Promise ๋ฉ”์„œ๋“œ ์ฒด์ด๋‹์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

  3. Promise๋Š” ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ์‰ฝ๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋„๋ก Promise ๋™์‹œ ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•œ all, allSettled, race, any์™€ ๊ฐ™์€ static methods๋ฅผ ์ง€์›ํ•œ๋‹ค.

3. Promise๊ฐ€ ํ•ด๊ฒฐํ•œ ๋ฌธ์ œ ๐Ÿ”ง

  • ์ด์ œ Promise ๋‚ด๋ถ€ ๋™์ž‘ ๋ฐฉ์‹์— ๋Œ€ํ•ด ํŒŒ์•…ํ–ˆ์œผ๋‹ˆ, ES6์—์„œ Promise๋ฅผ ๋„์ž…ํ•จ์œผ๋กœ์จ ํ•ด๊ฒฐํ•˜๊ณ ์ž ํ–ˆ๋˜ ๋ฌธ์ œ๊ฐ€ ๋ฌด์—‡์ธ์ง€์— ๋Œ€ํ•ด ์งš์–ด๋ณด์ž.

โœ…ย Javascript์˜ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ํŒจํ„ด์€ ์™œ ๋„์ž…๋˜์—ˆ๋Š”๊ฐ€

  • Javascript๋Š” single thread ์–ธ์–ด๋‹ค. ์ฆ‰, ๋‹จ ํ•˜๋‚˜์˜ call stack์„ ๊ฐ€์ง€๊ณ  ๋™์ž‘ํ•œ๋‹ค. ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ๋ฐฉ์‹์€ ํ•„์—ฐ์ ์œผ๋กœ ๋‹ค์ค‘ ์“ฐ๋ ˆ๋“œ๊ฐ€ ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, Javascript ํ™˜๊ฒฝ์—์„œ๋Š” ์ฝ”๋“œ์˜ ๋™๊ธฐ์  ์‹คํ–‰๋งŒ ๊ฐ€๋Šฅํ•˜๋‹ค.
  • ํ•˜์ง€๋งŒ ๋ชจ๋“  ์ฝ”๋“œ๋ฅผ ๋™๊ธฐ์ ์œผ๋กœ ์ˆ˜ํ–‰ํ•  ๊ฒฝ์šฐ, blocking์œผ๋กœ ์ธํ•œ ์„ฑ๋Šฅ ์ €ํ•˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ๋ฐ–์— ์—†๋‹ค. ์„œ๋ฒ„์—์„œ ์‘๋‹ต์„ ๋ฐ›์•„์˜ค๋Š” ๋“ฑ ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋Š” ์„ ํ–‰ task๊ฐ€ ๋๋‚˜์•ผ ์ดํ›„ task๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
  • ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด Javascript๋Š” ์›น ๋ธŒ๋ผ์šฐ์ €๋‚˜ Node.js ์‹คํ–‰ ํ™˜๊ฒฝ์˜ Web API์™€ Event loop์˜ ํž˜์„ ๋นŒ๋ ค ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.
  • ํ•˜์ง€๋งŒ ๋น„๋™๊ธฐ ๋ฐฉ์‹์„ ๋„์ž…ํ•จ์— ๋”ฐ๋ผ non-blocking์œผ๋กœ ์ธํ•ด ์‹คํ–‰ ์ˆœ์„œ๊ฐ€ ๋ณด์žฅ๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ํƒœ์ƒ์ ์ธ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค.
  • ์ด๋Ÿฌํ•œ ์ƒํ™ฉ ์†์—์„œ Javascript๋Š” ๋น„๋™๊ธฐ์—์„œ ํ•จ์ˆ˜์˜ ์‹คํ–‰ ์ˆœ์„œ๋ฅผ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•ด ์—ฌ๋Ÿฌ ์žฅ์น˜๋ฅผ ๋„์ž…ํ•˜์˜€์œผ๋ฉฐ, ๊ทธ ์ค‘ ๋Œ€ํ‘œ์ ์ธ ํŒจํ„ด์ด (1) callback (2) Promise (3) async/await ์ด๋‹ค.

โœ…ย Callback ํŒจํ„ด: (1) ๊ฐ€๋…์„ฑ ์ €ํ•˜ (2) ์—๋Ÿฌ ์ฒ˜๋ฆฌ ์ด์Šˆ

  • ์ฝœ๋ฐฑ ํŒจํ„ด์€ Javascript์—์„œ ๋น„๋™๊ธฐ ์ฝ”๋“œ์˜ ์‹คํ–‰ ์ˆœ์„œ๋ฅผ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ์ „ํ†ต์ ์ธ ์žฅ์น˜์ด๋‹ค.

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

    // ๋น„๋™๊ธฐ ํ•จ์ˆ˜
    const get = (url, callback) => {
    	const xhr = new XMLHttpRequest();
    	xhr.open('GET', url);
    	xhr.send()
    
    	xhr.onload = () => {
    		if (xhr.status === 200) {
    			callback(JSON.parse(xhr.response))
    		}
    		else {
    			console.error(`${xhr.status} ${xhr.statusText}`)
    		}
    	}
    }
    
    // callback hell
    get('/step1', a => {
    	get(`/step2/${a}`, b => {
    		get(`/step3/${b}`, c => {
    			get(`/ step4 / ${c}`, d => {
    				console.log(d);
    			})
    		})
    	})
    })
  • Javascript์—์„œ ์—๋Ÿฌ๋Š” ํ˜ธ์ถœ์ž ๋ฐฉํ–ฅ์œผ๋กœ ์ „๋‹ฌ๋œ๋‹ค.

    • ๋™๊ธฐ์  ์ž‘์—…์—์„œ๋Š” ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด, ์ด๋ฅผ ์ฒ˜๋ฆฌํ•  tryโ€ฆ catchโ€ฆ ์ ˆ์„ ๋งŒ๋‚ ๋•Œ๊นŒ์ง€ call stack์„ ๊ฑฐ์Šฌ๋Ÿฌ ์˜ฌ๋ผ๊ฐ€์„œ(bubbling up the call stack) ์˜ˆ์™ธ๊ฐ€ ์ฒ˜๋ฆฌ๋œ๋‹ค.
    • ๋ฐ˜๋ฉด, ๋น„๋™๊ธฐ ์ž‘์—…์—์„œ๋Š” ํ˜ธ์ถœ์ž๊ฐ€ call stack์— ์กด์žฌํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— tryโ€ฆ catchโ€ฆ๋ฅผ ํ†ตํ•ด ํ˜ธ์ถœ์ž์—๊ฒŒ ์˜ˆ์™ธ๋ฅผ ์ „๋‹ฌ ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ํƒœ์ƒ์  ํ•œ๊ณ„๊ฐ€ ์žˆ๋‹ค.
    try {
      setTimeout(() => {
        throw new Error("Error!")
      }, 5000)
    } catch (e) {
      console.error(e) // error catch ๋ถˆ๊ฐ€
    }

โœ…ย Promise ํŒจํ„ด: (1) ๋ฉ”์„œ๋“œ ์ฒด์ด๋‹์„ ํ†ตํ•ด ๊ฐ€๋…์„ฑ ๋ฌธ์ œ ํ•ด๊ฒฐ (2) catch๋ฅผ ํ†ตํ•œ ์—๋Ÿฌ ์ฒ˜๋ฆฌ

  • ์•ž์„œ ์‚ดํŽด๋ณธ ์ฝœ๋ฐฑ ํŒจํ„ด์˜ (1) ๊ฐ€๋…์„ฑ ์ €ํ•˜ (2) ์—๋Ÿฌ ์ฒ˜๋ฆฌ ์ด์Šˆ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ES6์— ๋„์ž…๋œ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ์žฅ์น˜๊ฐ€ ๋ฐ”๋กœ Promise์ด๋‹ค.

  • ์šฐ์„ , Promise๋Š” ์ค‘์ฒฉ๋œ ์ฝœ๋ฐฑ์„ ์„ ํ˜•์— ๊ฐ€๊นŒ์šด ํ”„๋ผ๋ฏธ์Šค ์ฒด์ธ์œผ๋กœ ๋ฐ”๊พธ์–ด ๊ฐ€๋…์„ฑ์„ ํ–ฅ์ƒ ์‹œ์ผœ์ค€๋‹ค.

    myPromise()
      .then((message) => {
        console.log("Success case1: ", message)
      })
    	.then((message) => {
        console.log("Success case2: ", message)
      })
      .catch((error) => {
        console.log(error.name, error.message)
      })
    	.finally(() => {
    		consoel.log('End')
    	})
  • Promise๋Š” ๋น„๋™๊ธฐ ์ž‘์—…์˜ ํƒœ์ƒ์  ํ•œ๊ณ„์ธ ์—๋Ÿฌ ์ฒ˜๋ฆฌ์˜ ์–ด๋ ค์›€์„ catch ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ํ•ด๊ฒฐํ•œ๋‹ค.

    • Promise ๊ธฐ๋ฐ˜ ๋น„๋™๊ธฐ ์ž‘์—…์€ ์˜ˆ์™ธ๋ฅผ then(thenCb, catchCb)์˜ catchCb์— ์ „๋‹ฌํ•œ๋‹ค.
    • Promise ์ฒด์ด๋‹์—์„œ ๋ฐœ์ƒํ•œ ์—๋Ÿฌ๋Š” catch()๋ฅผ ๋งŒ๋‚  ๋•Œ๊นŒ์ง€ ์ฒด์ธ์„ ๋”ฐ๋ผ ๋‚ด๋ ค๊ฐ„๋‹ค(trickling down the chain).
      • ์ด ๋•Œ, then() ๋ฉ”์„œ๋“œ ๋‚ด๋ถ€์—์„œ ๋™๊ธฐ์  throw ๋ฌธ์œผ๋กœ ๋ฐœ์ƒ๋œ Error ๊ฐ์ฒด๊นŒ์ง€๋„ catch() ๋ฉ”์„œ๋“œ์— ์˜ํ•ด ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.
  • [๋” ๋‚˜์•„๊ฐ€๊ธฐ] Q. Promise then(onSuccess, onFailure)์™€ then(onSuccess).catch(onFailure)๋Š” ๋ฌด์—‡์ด ๋‹ค๋ฅผ๊นŒ?

    promise.then(f, f) vs promise.then(f).catch(f) ๋Š” ๋ฌด์—‡์ด ๋‹ค๋ฅผ๊นŒ?

    • catch(onFailure)๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ, then ๋ฉ”์„œ๋“œ ๋‚ด๋ถ€์—์„œ ๋ฐœ์ƒํ•œ reject์— ๋Œ€ํ•œ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค. ์ฆ‰,
    • ๋”ฐ๋ผ์„œ, ๋‚ด๊ฐ€ ์ž ์žฌ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‹ถ์€ ๋ช…ํ™•ํ•œ failure๊ฐ€ ์žˆ๋‹ค๋ฉด,ย promise.then(oSuccess, onFailure)๋ฅผ ์“ฐ๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.
    • ๋ฐ˜๋ฉดย promise.catch(onFailure)๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ์˜ˆ์ธกํ•˜์ง€ ๋ชปํ•œ ๊ฒฝ์šฐ๋ฅผ ํฌํ•จํ•œ ๋ชจ๋“  ์—๋Ÿฌ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

4. Promise์˜ ํ•œ๊ณ„ ๐Ÿ‘ฟ

  • ์ •๋ฆฌํ•˜๋ฉด, Promise๋Š” Javascript ๋น„๋™๊ธฐ ์ž‘์—…์˜ ์‹คํ–‰ ์ˆœ์„œ๋ฅผ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•ด ์ „ํ†ต์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋˜ callback ํŒจํ„ด์˜ ๊ฐ€๋…์„ฑ๊ณผ ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๋ถ€๋ถ„์„ ๊ฐœ์„ ํ•œ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ํŒจํ„ด์ด๋‹ค.
  • ๋” ๋‚˜์•„๊ฐ€ โœ…ย Promise๋Š” ์ด ์™ธ์—๋„ ๋‹ค์–‘ํ•œ static method๋“ค์„ ์ œ๊ณตํ•˜์—ฌ ๊ฐ„๋‹จํžˆ ๋น„๋™๊ธฐ ํ›„์† ์ฒ˜๋ฆฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ค€๋‹ค. ์ด๋Ÿฌํ•œ ๋งฅ๋ฝ์—์„œ Promise = callback ํŒจํ„ด์˜ syntatic sugar + alpha ๋ผ๊ณ  ์ •๋ฆฌํ•ด ๋ณผ ์ˆ˜ ์žˆ๋‹ค.
  • ํ•˜์ง€๋งŒ ์ธ๊ฐ„์˜ ์š•์‹ฌ์€ ๋์ด ์—†๋‹คโ€ฆ ๊ฐœ๋ฐœ์ž๋“ค์€ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ํŒจํ„ด์ด ๋งˆ์น˜ ๋™๊ธฐ ์ฝ”๋“œ ์ˆ˜์ค€์˜ ๊ฐ€๋…์„ฑ์„ ๊ฐ€์ง€๊ธธ ์›ํ–ˆ๊ณ , ์ด๋Ÿฌํ•œ ์š”๊ตฌ ํ•˜์— async/await ํŒจํ„ด์ด ๋“ฑ์žฅํ•˜๊ฒŒ ๋œ๋‹ค. async/await ํŒจํ„ด์€ Generator๋ฅผ ํ†ตํ•ด ๊ตฌํ˜„๋˜์–ด ์žˆ์–ด tryโ€ฆ catchโ€ฆ์— ์˜ํ•œ ๋น„๋™๊ธฐ ์—๋Ÿฌ ์ฒ˜๋ฆฌ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published