- ์ด ํ๋ก์ ํธ์์๋ Javascript
Promise๋์ ๋ฐฉ์์ ์ดํดํ๊ธฐ ์ํด, ์ด์ ๋์ผํ ๊ธฐ๋ฅ์ ์ํํ๋ ์ปค์คํ ํด๋์คMyPromise๋ฅผ ์ง์ ๊ตฌํํด ๋ณด์๋ค.
- ํต์ฌ๋ง ์๊ณ ์ํ๋ฉด ์ธ๋ถ ๊ตฌํ์ ๊ฑด๋ ๋ฐ๊ณ 2. Promise ๋ด๋ถ ๋์ ๋ฐฉ์ ๐๏ธ๋ง ์ฝ์ด๋ ์ถฉ๋ถํ๋ค.
- ๋ค์ด๊ฐ๋ฉฐ
- Promise๋ ๋์ฒด ๋ฌด์์ธ๊ฐ ๐ง๐ปโ๐ป
- Promise ๋ด๋ถ ๋์ ๋ฐฉ์ ๐๏ธ
- Promise๊ฐ ํด๊ฒฐํ ๋ฌธ์ ๐ง
- Promise์ ํ๊ณ ๐ฟ
- ๋ง์ฝ README.md ํ์ผ ํ์์ผ๋ก ์ฝ๊ธฐ ํ๋ค๋ค๋ฉด, Promise ์ง์ ๋ง๋ค์ด์ ์ดํดํ์ ํด๋น ๋งํฌ์์ ๋ ํธํ๊ฒ ํด๋น ํ๋ก์ ํธ README๋ฅผ ์ฝ์ ์ ์๋ค.
- ๋น๋๊ธฐ ์ฒ๋ฆฌ์๋ ๋ฌด์กฐ๊ฑด
async/awaitํจํด๋ง ์ฌ์ฉํ๋ค๊ฐ, Javascript์ ๋ํ์ ๋น๋๊ธฐ ์ฒ๋ฆฌ ๋ฐฉ์์ธ (1) ์ฝ๋ฐฑ ํจํด (2) Promise ํจํด (3) async/await ํจํด๊ฐ๊ฐ์ ์ฅ๋จ์ ์ ์๊ณ ์จ์ผํ์ง ์์๊นํ๋ ์๊ฐ์ด ๋ถํ๋ฏ ๋ค์๋ค. (์ด ๊ฐ์ ๊ฑด๋์ง ๋ง์์ด์ผ ํ๋คโฆ) - ์์ค์ ์๋ฐ์คํฌ๋ฆฝํธ ์์ต์, ์ ๋ช ๋ธ๋ก๊ทธ ํฌ์คํธ๋ฅผ ๋ค์ ธ๊ฐ๋ฉฐ ๊ฐ ํจํด์ ์ฅ๋จ์ ์ ํ ์คํธ ํํ๋ก ํ์ตํ์ง๋ง, ์ฝ๋๋ก ์ฎ๊ธฐ์ง ์์ผ๋ ๋ํต ์๋ฟ์ง ์๋๋ค.
์ง์ Promise๋ฅผ ๊ตฌํํด๋ณด๋ฉด, ์ฝ๋ฐฑ ํจํด์ ํ๊ณ๋ฅผ Promise๊ฐ ์ด๋ป๊ฒ ํด๊ฒฐํ๋ ค ํ๋์ง ์ดํดํ ์ ์์ง ์์๊น?๋ผ๋ ๋จ์ดํ ์๊ฐ์์ ์ถ๋ฐํ ํ๋ก์ ํธ๋ฅผ ์๊ฐํ๋ค.
- ํ๋จ์
Promise๋ฅผ ์ง์ ์์ฑํcustom Promise์ธMyPromise์ธ๋ถ ์ฝ๋์ ๋ํ ์ค๋ช ์ด๋ค. ์ดํด๊ฐ ๋์ง ์๋ ๋ถ๋ถ์ด ์๋ค๋ฉด ํผ์ณ ์ธ๋ถ ๊ตฌํ ํ์ธํด๋ณด์.
- 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๊ฐ ํฌํจ๋๋ค.
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 ํจ์
}
```
- 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)
})
```
```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
}
)
}
}
```
-
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)์ธ์๋ก ์ฌ์ฉ๋๋ค.
```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()
}
}
```
- Javascript์์
promiseํ์์ฒ๋ฆฌ ๋ฉ์๋์ธthen,catch,finally๋ ์ธ์ ๋ ์๋ก์ดpromise๋ฅผ ์์ฑํด ๋ฐํํด์ค๋ค. ์ด์ฒ๋ผ ํ์์ฒ๋ฆฌ ๋ฉ์๋๊ฐ ํญ์promise๋ฅผ ๋ฐํ๋๋ค๋ ์ฝ์์ ์งํค๊ธฐ ๋๋ฌธ์, ๊ฐ๋ฐ์๋promiseํ์ ์ฒ๋ฆฌ ๋ฉ์๋๋ค์ ์ฒด์ด๋ํด ์ฌ์ฉํ ์ ์๋ค.- ํ์ ์ฒ๋ฆฌ ๋ฉ์๋์ ์ฝ๋ฐฑํจ์๊ฐ (1)
promise๋ฅผ ๋ฐํํ๋ ๊ฒฝ์ฐ, ํด๋นpromise๋ฅผ ๊ทธ๋๋ก ๋ฐํํ๋ค. - ๋ฐ๋ฉด, (2) ์ฝ๋ฐฑํจ์๊ฐ promise๊ฐ ์๋ ๊ฐ์ ๋ฐํํ๋ฉด, ํด๋น๊ฐ์
resolve๋๋rejectํจ์๋ก ๊ฐ์ธ์ฃผ๋ฉดpromiseํํ๋ก ๋ฐํ๋๋ค.
- ํ์ ์ฒ๋ฆฌ ๋ฉ์๋์ ์ฝ๋ฐฑํจ์๊ฐ (1)
-
์์ ๋ง๋ 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์ฒด์ด๋ ํ ์คํธ ์ฝ๋๋ฅผ ๋ชจ๋ ํต๊ณผํ ์ ์๋ค.
-
Javascript์์ ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฅผ ์ํด
Promise๋ด๋ถ์ ๋ฑ๋ก๋ ์ฝ๋ฐฑํจ์๋ค์microtask queue์ ๋ค์ด๊ฐ ์ฐจ๋ก๋ฅผ ๊ธฐ๋ค๋ฆฐ๋ค. -
์ดํ Javascript
Event loop์ ์ํด ์ฝ์คํ์ด ๋น์ด์๋ ๊ฒฝ์ฐ,microtask queue์ ๋๊ธฐ์ค์ธ ์ฝ๋ฐฑ ํจ์๋ค์ดcall stack์ผ๋ก ์ด๋๋์ด ์คํ๋๋ค.microtask queue์ ์ฐ์ ์์๋event queue(= callback queue, task queue)์ ์ฐ์ ์์๋ณด๋ค ๋๋ค.
-
์ง๊ธ๊น์ง๋ ๋น๋๊ธฐ ์ฒ๋ฆฌ์ ๋ํ ๊ณ ๋ ค ์์ด
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 = [] } }) }
-
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์๋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์ ๋ํ ํ ์คํธ ์ฝ๋ ๋ํ ๋ชจ๋ ํต๊ณผํ ์ ์๋ค.

-
- Promise๋ฅผ ์ง์ ์ฝ๋๋ก ์์ฑํด๋ณด๋, ์ด์ ์ผ Promise๊ฐ ๋ฌด์์ธ์ง ์๋ฟ๋๋ค. ์ฝ๋๋ฅผ ์น๋ฉฐ ์ดํดํ๊ฒ๋ Promise์ ๋ด๋ถ ๋์ ๋ฐฉ์์ ๊ฐ๋จํ ์์ฝํด๋ณด์๋ค.
๐ก Promise = ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฅผ ์ํด state, result, ์ฌ๋ฌ callback ๋ฐฐ์ด์ ๊ด๋ฆฌํ๋ ๊ฐ์ฒด
Promise ํ์ ์ฒ๋ฆฌ ๋ฉ์๋ then, catch, finally๋ฅผ ํตํด ๋ฑ๋กํ ์ฝ๋ฐฑํจ์๋ Promise ๋ด๋ถ์ ๋ฐฐ์ด ํํ๋ก ์ ์ฅ๋๊ณ , Promise state๊ฐ ๋ณ๊ฒฝ๋๋ฉด ํด๋น ์ํ์ ๋ฐ๋ผ ์ ํ์ ์ผ๋ก forEach๋ฌธ์ ํตํด callback ๋ฐฐ์ด์ ์ํํ๋ค. ๊ฐ ์ฝ๋ฐฑ์ ์ธ์๋ก result๊ฐ ๋ค์ด๊ฐ๋ค. ์ด ๋, ์ฝ๋ฐฑ ํจ์๋ค์ microtask queue์ ๋ฑ๋ก๋๋ค.
Promise ์ฝ๋๋ฅผ ๋ณด๋ฉด, ํ์ ์ฒ๋ฆฌ ๋ฉ์๋๋ ๋ชจ๋ Promise๋ฅผ ๋ฐํํ๋ค. ๋๋ถ์ ๊ฐ๋ฐ์๋ Promise ๋ฉ์๋ ์ฒด์ด๋์ ์ํํ ์ ์๋ค.
Promise๋ ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฅผ ์ฝ๊ฒ ํ ์ ์๋๋ก Promise ๋์ ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํ all, allSettled, race, any์ ๊ฐ์ static methods๋ฅผ ์ง์ํ๋ค.
- ์ด์ Promise ๋ด๋ถ ๋์ ๋ฐฉ์์ ๋ํด ํ์ ํ์ผ๋, ES6์์ Promise๋ฅผ ๋์ ํจ์ผ๋ก์จ ํด๊ฒฐํ๊ณ ์ ํ๋ ๋ฌธ์ ๊ฐ ๋ฌด์์ธ์ง์ ๋ํด ์ง์ด๋ณด์.
- 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 ์ด๋ค.
-
์ฝ๋ฐฑ ํจํด์ 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 ๋ถ๊ฐ }
- ๋๊ธฐ์ ์์
์์๋ ์๋ฌ๊ฐ ๋ฐ์ํ๋ฉด, ์ด๋ฅผ ์ฒ๋ฆฌํ
-
์์ ์ดํด๋ณธ ์ฝ๋ฐฑ ํจํด์ (1) ๊ฐ๋ ์ฑ ์ ํ (2) ์๋ฌ ์ฒ๋ฆฌ ์ด์๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ES6์ ๋์ ๋ ๋น๋๊ธฐ ์ฒ๋ฆฌ ์ฅ์น๊ฐ ๋ฐ๋ก
Promise์ด๋ค. -
์ฐ์ ,
Promise๋ ์ค์ฒฉ๋ ์ฝ๋ฐฑ์ ์ ํ์ ๊ฐ๊น์ด ํ๋ผ๋ฏธ์ค ์ฒด์ธ์ผ๋ก ๋ฐ๊พธ์ด ๊ฐ๋ ์ฑ์ ํฅ์ ์์ผ์ค๋ค.- ์ง์ ๊ตฌํํ
MyPromise์ฝ๋์์ ์ดํด๋ณผ ์ ์๋ฏ, โ ย Promise ํ์์ฒ๋ฆฌ ๋ฉ์๋๋ ํญ์ Promise๋ฅผ ๋ฐํํ๊ธฐ ๋๋ฌธ์ Promise ๋ฉ์๋ ์ฒด์ด๋์ด ๊ฐ๋ฅํ๋ค. - ์ฆ,
then,catch,finally๋ฉ์๋๋ฅผ ํตํด ์ฝ๋ฐฑ ํจ์๋ฅผ ์ฐ์ด์ด ๋ฑ๋กํ ์ ์๊ธฐ ๋๋ฌธ์ ๋น๋๊ธฐ ์ค์ฒฉ์ผ๋ก ์ธํ ์ฝ๋ฐฑํฌ์ด ๋ฐ์ํ์ง ์๋๋ค.
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)๋ ๊ฐ๋ฐ์๊ฐ ์์ธกํ์ง ๋ชปํ ๊ฒฝ์ฐ๋ฅผ ํฌํจํ ๋ชจ๋ ์๋ฌ๋ฅผ ์ฒ๋ฆฌํ ์ ์๋ค.
- ์ ๋ฆฌํ๋ฉด, Promise๋ Javascript ๋น๋๊ธฐ ์์ ์ ์คํ ์์๋ฅผ ๋ณด์ฅํ๊ธฐ ์ํด ์ ํต์ ์ผ๋ก ์ฌ์ฉํ๋ callback ํจํด์ ๊ฐ๋ ์ฑ๊ณผ ์๋ฌ ์ฒ๋ฆฌ ๋ถ๋ถ์ ๊ฐ์ ํ ๋น๋๊ธฐ ์ฒ๋ฆฌ ํจํด์ด๋ค.
- ๋ ๋์๊ฐ โ ย Promise๋ ์ด ์ธ์๋ ๋ค์ํ static method๋ค์ ์ ๊ณตํ์ฌ ๊ฐ๋จํ ๋น๋๊ธฐ ํ์ ์ฒ๋ฆฌ๋ฅผ ํ ์ ์๋๋ก ๋์์ค๋ค. ์ด๋ฌํ ๋งฅ๋ฝ์์ Promise = callback ํจํด์ syntatic sugar + alpha ๋ผ๊ณ ์ ๋ฆฌํด ๋ณผ ์ ์๋ค.
- ํ์ง๋ง ์ธ๊ฐ์ ์์ฌ์ ๋์ด ์๋คโฆ ๊ฐ๋ฐ์๋ค์ ๋น๋๊ธฐ ์ฒ๋ฆฌ ํจํด์ด ๋ง์น ๋๊ธฐ ์ฝ๋ ์์ค์ ๊ฐ๋
์ฑ์ ๊ฐ์ง๊ธธ ์ํ๊ณ , ์ด๋ฌํ ์๊ตฌ ํ์
async/awaitํจํด์ด ๋ฑ์ฅํ๊ฒ ๋๋ค.async/awaitํจํด์Generator๋ฅผ ํตํด ๊ตฌํ๋์ด ์์ดtryโฆ catchโฆ์ ์ํ ๋น๋๊ธฐ ์๋ฌ ์ฒ๋ฆฌ๋ ๊ฐ๋ฅํ๋ค.

