๐ ์ ๋๋ ์ดํฐ์ Async-Await
EO ์ฑ๋์ ์๋์ด ๊ฐ๋ฐ์๋ถ๋ค์ ์ด๋ ฅ์ ๊ด๋ จ ํ์ ๋ง์ํด ์ฃผ์๋ ์์์ ๋ณธ ์ ์ด ์๋ค. ๊ทธ๋ ํ ์๋์ด ๊ฐ๋ฐ์๋ถ๊ป์ "skill๋์ ์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ์ํ๋ค๊ณ ํ๋ฉด์ ์ ๋๋ ์ดํฐ๋ฅผ ๋ฌผ์ด๋ณด๋ฉด ์ ๋๋ก ์ค๋ช ๋ชปํ๋ ์ฌ๋์ ์๋ค"๋ผ๊ณ ๋ง์ํ์ จ๋ค. ๊ทธ ๋ง์์ "์ ๋๋ ์ดํฐ? ์ดํฐ๋ฌ๋ธ ๊ฐ์ฒด๋ฅผ ํธํ๊ฒ ๋ง๋ค ์ ์๋ ๊ฒ ์๋๊ฐ"๋ผ๊ณ ๋๋ ์๊ณ ์๋ค๊ณ ์๊ฐํ๋ค. ํ์ง๋ง ๊ณต๋ถํ๋ฉด์ ์ ์ ๋๋ ์ดํฐ๊ฐ ์ค์ํ ์ง, ์ด๋ป๊ฒ ์ฐ์ด๊ณ ์๋์ง๋ฅผ ๋ณด๋ ๋๋ ์ ๋๋ ์ดํฐ๋ฅผ ๋ชฐ๋๋ค๋ ์ฌ์ค์ ๊นจ๋ฌ์ ์ ์์๋ค.
์ด์ ๋ ์ ๋๋ก ์ดํดํ๊ณ ์ค๋ช ํ ์ ์๊ฒ ์ ๋๋ ์ดํฐ์ ์ ๋๋ ์ดํฐ๊ฐ ์ด๋ป๊ฒ ํ์ฉ๋๊ณ ์๋์ง ์ ๋ฆฌํด ๋ณด๊ณ ์ ํ๋ค.
๐ ์ ๋๋ ์ดํฐ
์ ๋๋ ์ดํฐ๋ "์ดํฐ๋ฌ๋ธ ๊ฐ์ฒด"๋ฅผ ๋ง๋ ๋ค. ๊ทธ๋ฌ๋ฉด ์ดํฐ๋ฌ๋ธ ๊ฐ์ฒด๋ ๋ฌด์์ธ์ง ๋จผ์ ์ ๋ฆฌํด ๋ณด๊ณ ์ ํ๋ค.
์ดํฐ๋ฌ๋ธ ๊ฐ์ฒด
์ดํฐ๋ฌ๋ธ ๊ฐ์ฒด (iterable object)๋ ์ด์ ์ iteration์ ๋ํด ๊ณต๋ถํ๋ฉด์ ์ ๋ฆฌํ ์ ์ด ์์ง๋ง, ์์ง ์์ ํ ๋ฐ์ ๋ค์ฌ์ง์ง ์์ ๋ค์ ํ ๋ฒ ์ ๋ฆฌ ํด๋ณด๋ ค ํ๋ค.
์ดํฐ๋ฌ๋ธ ๊ฐ์ฒด๋ ์ดํฐ๋ฌ๋ธ ํ๋กํ ์ฝ๊ณผ ์ดํฐ๋ ์ดํฐ ํ๋กํ ์ฝ ๋ ๊ฐ์ง๋ฅผ ๋ง์กฑํด์ผ ํ๋ค.
๋จผ์ ์ดํฐ๋ฌ๋ธ ํ๋กํ ์ฝ์ ์ ๊ทธ๋ฆผ์ ์ผ์ชฝ์ ์กฐ๊ฑด์ผ๋ก ๊ฐ์ฒด ๋ด์ [Symbol.iterator]๋ฅผ ํค๋ก ํ ๋ฉ์๋๊ฐ ์กด์ฌํ๋ ๊ฒ์ ์๋ฏธํ๋ค. ์ด๋ [Symbol.iterator] ๋ฉ์๋์ ๋ฐํ๊ฐ์ด next๋ฅผ ๋ฉ์๋๋ฅผ ๊ฐ์ง๋ ๊ฐ์ฒด์ฌ์ผํ๋๋ฐ ์ด๊ฒ์ ์ดํฐ๋ ์ดํฐ ํ๋กํ ์ฝ์ด๋ผ๊ณ ๋ถ๋ฅธ๋ค. next๋ฉ์๋๋ ์ํํ๋ฉฐ value,done ์์ฑ์ ๊ฐ๋ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ค.
์ด๋ ๊ฒ ๋ ๊ฐ์ง ์กฐ๊ฑด์ ๋ง์กฑํ ์ดํฐ๋ฌ๋ธ ๊ฐ์ฒด๋ for-of๋ก ์ํ๊ฐ ๊ฐ๋ฅํ ํน์ง์ ๊ฐ์ง๋ฉฐ, ๋ํ์ ์ธ ์๋ก ๋ฐฐ์ด์ด ์๋ค.
const fibonacci = {
[Symbol.iterator]() {
let [pre, cur] = [0, 1]
const max = 10
return {
next() {
;[pre, cur] = [cur, pre + cur]
return { value: cur, done: cur >= max }
},
}
},
}
for (const num of fibonacci) {
console.log(num)
}์ดํฐ๋ฌ๋ธ ๊ฐ์ฒด์ ์ ๋๋ ์ดํฐ
์์ ์ธ๊ธํ ๋๋ก ์ ๋๋ ์ดํฐ๋ ์ดํฐ๋ฌ๋ธ ๊ฐ์ฒด๋ฅผ ๋ง๋ค ์ ์๋ค. ์ ๋๋ ์ดํฐ๋ ์ ์ธ์, function* ๋ก ์์ํ๊ณ yield ๋ฌธ์ ํ๋ ์ด์ ํฌํจํ๋ค. yield๋ ์ ๋๋ ์ดํฐ๋ก ๋ง๋ค์ด์ง ์ดํฐ๋ฌ๋ธ ๊ฐ์ฒด์ next ๋ฉ์๋์ ํธ์ถ์ ๋ฐ๋ผ ํจ์ ๋ด๋ถ์ ์คํ์ ์ค์งํ๊ฑฐ๋ ๋ฐํํ๋ค. ์ฌ๊ธฐ์ ์ค์ํ ์ ์ ์ ๋๋ ์ดํฐ๋ก ํจ์ ๋ด๋ถ ์คํ์ ์ ์ดํ ์ ์๋ค๋ ์ ์ด๋ค.
์์ ๋ง๋ค์๋ ์ดํฐ๋ฌ๋ธ ๊ฐ์ฒด fibonacci๋ฅผ ์ ๋๋ ์ดํฐ๋ก ๋ค์ ๋ง๋ค๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.
const fibonacciGen = (function* () {
let [pre, cur] = [0, 1]
const max = 10
while (pre + cur <= max) {
;[pre, cur] = [cur, pre + cur]
yield cur
}
})()
for (const num of fibonacciGen) {
console.log(num)
}์ด์ ์ ๋๋ ์ดํฐ๊ฐ "์ด๋ป๊ฒ ํจ์ ๋ด๋ถ ์คํ์ ์ ์ดํ๋์ง" ๋ ๊ฐ์ง ์์ ๋ก ์์๋ณด์. ์ฒซ ๋ฒ์งธ ์์ ์ฝ๋๋ฅผ ๋ณด๋ฉด generator๋ ์ ๋๋ ์ดํฐ๋ก ๋ง๋ ์ดํฐ๋ฌ๋ธ ๊ฐ์ฒด๋ฅผ ๋ฐํ ๋ฐ๋๋ค. next ๋ฉ์๋๋ฅผ ์ด์ฉํ๋ฉด value,done์ key๋ก ํ๋ ๊ฐ์ฒด๊ฐ ๋ฐํ๋๋๋ฐ, ์ฌ๊ธฐ์ ์ค์ํ ์ ์ next๊ฐ ํธ์ถ๋ ๋๋ง๋ค "yield๋ฌธ๊น์ง ์งํ๋๊ณ ๋ฉ์ถ๋ค๋ ์ "์ด๋ค. yield๋ฌธ์ด ๋ ์ด์ ์์ ๋๋ value๋ก undefined, done์ true๋ก ๋ฐํํด ์ค๋ค.
function* genFunc() {
try {
yield 1
yield 2
yield 3
} catch (e) {
console.error(e)
}
}
const generator = genFunc()
console.log(generator.next()) // { value: 1, done: false }
console.log(generator.next()) // { value: 2, done: false }
console.log(generator.next()) // { value: 3, done: false }
console.log(generator.next()) // { value: undefined, done: true }๋๋ฒ์งธ ์์ ๋ yield๋ฅผ ์ด์ฉํด ๊ฐ์ ํ ๋นํ ์์ ๋ค. ์คํ ๊ณผ์ ์ ์ ๋ฆฌํ๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.
- res ์ฒซ ๋ฒ์งธ ํธ์ถ: yield 1๊น์ง ์คํํ๊ณ ์งํ์ ๋ฉ์ถ๋ค.
{ value:1, done:false }๋ฅผ ๋ฐํํ๋ค. - res ๋ ๋ฒ์งธ ํธ์ถ: next(10)์ผ๋ก ์ ๋ฌ ๋ฐ์ 10์ x์ ํ ๋นํ๊ณ , x+10๊น์ง ์คํํ๊ณ ๋ฉ์ถ๋ค.
{ value: 20, done: false }๋ฅผ ๋ฐํํ๋ค. - res ์ธ ๋ฒ์งธ ํธ์ถ: next(20)์ผ๋ก ์ ๋ฌ ๋ฐ์ 20์ y์ ํ ๋นํ๊ณ ,
{ value: 30, done: true }๋ฅผ ๋ฐํํ๋ค.
function* genFunc() {
const x = yield 1
console.log("x", x) // x 10
const y = yield x + 10
console.log("y", y) // y 20
return x + y
}
const generator = genFunc(0)
let res = generator.next()
console.log(res) // { value: 1, done: false }
res = generator.next(10)
console.log(res) // { value: 20, done: false }
res = generator.next(20)
console.log(res) // { value: 30, done: true }
console.log(generator.next()) // { value: undefined, done: true }์ ๋๋ ์ดํฐ๊ฐ ์ด๋ป๊ฒ ํจ์ ๋ด๋ถ ์คํ์ ์ ์ดํ๋์ง์ ๋ํด ์์๋ดค๋ค. ๊ทธ๋ฌ๋ฉด ์ ๋๋ ์ดํฐ๋ฅผ ์ด๋์ ์ฌ์ฉํด์ผ ํ ๊น?
๐งจ ์ ๋๋ ์ดํฐ์ ํ์ฉ: Async-Await
์ ๋๋ ์ดํฐ๋ ์ฌ์ค ์ด๋ฏธ ๋ง์ด ์ฌ์ฉ๋๊ณ ์์๋ค. ๋ฐ๋ก async- await ๊ตฌ๋ฌธ์ด๋ค. async-await์ ๋จผ์ ์ ๋ฆฌํ๋ ํ๋ก๋ฏธ์ค๋ฅผ ๋๊ธฐ์ ์ผ๋ก ์ฝ๋๋ฅผ ์์ฑํ ์ ์๊ฒ ํด์ฃผ๊ณ ๋ฐํํ ๋๋ ํ๋ก๋ฏธ์ค๋ก ๋ฐํํด์ฃผ๋ ๊ธฐ๋ฅ์ ๊ฐ์ง๋ค. ์ด๋ ๊ฒ ๊ฐ๋ฅํ๋ ๊ฒ์ async-await์ด ๋ด๋ถ์ ์ผ๋ก ์ ๋๋ ์ดํฐ๋ฅผ ์ด์ฉํด ๊ตฌํ๋์ด ์์๊ธฐ ๋๋ฌธ์ด๋ค.
์๋๋ ๊ฐ๋จํ async-await์ ๊ตฌํํ ์ฝ๋์ด๋ค. ์ ๋๋ ์ดํฐ๊ฐ ๊ฐ์ง๋ ํน์ง, next์ yield๋ก ํจ์ ํธ์ถ์์ ํจ์์ ์ํ๋ฅผ ์ ์ ์๋ ์ ์ ์ด์ฉํ๋ค. ํจ์ ๋์์ ๊ฐ๋จํ๊ฒ ์ ๋ฆฌํ๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.
- asyncํจ์๋ ์ ๋ฌ ๋ฐ์ generatorํจ์๋ก ์ดํฐ๋ฌ๋ธ ๊ฐ์ฒด๋ฅผ ๋ฑ๋กํ ํ์, generator์ next์ ๊ฐ์ ๋ฐํํ๋ ํด๋ก์ ํจ์ onResolved๋ฅผ ๋ฐํํ๋ค.
- ์ฆ์ ์คํ ํจ์๋ก, ๋ฐํ๋ onResolved๋ฅผ ์คํํ๊ณ , ์ฒซ๋ฒ์งธ yield๋ฌธ์ fetch(url)์ ์งํํด result๋ก ๊ฒฐ๊ณผ๋ฅผ ๋ฐํ๋ฐ๋๋ค.
- ์์ง fetchTodoํจ์์ ๋๊น์ง ์งํ๋์ง ์์ result์ done์ด false์ด๋ฏ๋ก ๋ค์ onResolved๋ฅผ ์คํํ๋ค.
- ๋ ๋ฒ์งธ onResolved์คํ์ผ๋ก fetchTodo์ response๊ฐ์ ํ ๋นํ๊ณ , ๋ ๋ฒ์งธ yield๋ฌธ์ response.json()์ ์งํํด result๋ก ๊ฒฐ๊ณผ๋ฅผ ๋ฐํ๋ฐ๋๋ค.
- ์์ง fetchTodoํจ์์ ๋๊น์ง ์งํ๋์ง ์์ result์ done์ด false์ด๋ฏ๋ก ๋ค์ onResolved๋ฅผ ์คํํ๋ค.
- ์ธ ๋ฒ์งธ onResolved์คํ์ผ๋ก fetchTodo์ todo๊ฐ์ ํ ๋นํ๊ณ console์ ํธ์ถํ ๋ค์ result๋ก ๊ฒฐ๊ณผ๋ฅผ ๋ฐํ๋ฐ๋๋ค.
- fetchTodo๊ฐ ๋๋ฌ๊ธฐ ๋๋ฌธ์ result.done์ true๊ฐ๋์ด undefined๋ฅผ ๋ฐํํ๋ฉฐ ์ข ๋ฃํ๋ค.
const async = generatorFunc => {
const generator = generatorFunc()
const onResolved = arg => {
const result = generator.next(arg)
return result.done
? result.value
: result.value.then(res => onResolved(res))
}
return onResolved
}
async(function* fetchTodo() {
const url = "https://jsonplaceholder.typicode.com/todos/1"
const response = yield fetch(url)
const todo = yield response.json()
console.log(todo)
})()Async- Await
async,await์ ์์ ์์ ๋ณด๋ค ํจ์ฌ ๊ฐ๋ ์ฑ์ด ์ข๊ฒ ์ด์ฉ๋ ์ ์๊ฒ ์ถ๊ฐ๋ ๋ฌธ๋ฒ์ผ๋ก ๋น๋๊ธฐ ๋ก์ง์ ๋๊ธฐ์ ์ผ๋ก ์์ฑ์ด ๊ฐ๋ฅํ๊ฒ ๋์์ค๋ค. ์ฃผ์ํ ์ ์ ํญ์ ๋ฐํ๊ฐ์ Promise๋ผ๋ ์ ์ด๋ค. Typescript๋ก ์์ ํ๋ฉด์ async-await์ ์ด์ฉํ๋ฉด ๋๊ธฐ์ ์ผ๋ก ์์ฑํ๋ค ๋ณด๋ ์๋ชป ํ์ ์ ์ ๋ฌํด ์ค ๊ฒฝ์ฐ๊ฐ ์์๋ค. async- await์ ์ฅ์ ์ promise chaining์์ then,catch,finally๋ก ์ฐ๊ฒฐํ๋ค ๋ณด๋ฉด callback hell์ฒ๋ผ ๊ฐ๋ ์ฑ์ด ๋จ์ด์ง๊ฒ ๋ ์ ์์ ๋, ๊ฐ๋ ์ฑ์ ๋์ฌ์ค ์คํ ์์๋ฅผ ์์ธกํ ์ ์๋ ์ฅ์ ์ ๊ฐ์ง๊ฒ ๋๋ค. ๋ ๋ค๋ฅธ ์ฅ์ ์ผ๋ก ๋๊ธฐ์ ์ฝ๋์ฒ๋ผ try-catch๊ตฌ๋ฌธ์ผ๋ก ์๋ฌํธ๋ค๋ง์ด ๊ฐ๋ฅํ๋ค.
์์ ์์ ๋ฅผ ์ค์ async-await์ผ๋ก ๊ณ ์ณ๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ๋ค. ํจ์ฌ ๊ฐ๋จํ๊ฒ ๊ตฌํ๋ ๊ฒ์ ์ ์ ์๋ค.
async function fetchTodo() {
const url = "https://jsonplaceholder.typicode.com/todos/1"
const response = await fetch(url)
const todo = await response.json()
console.log(todo)
}await์ promise๊ฐ settled๋ ์ํ(์ฑ๊ณต,์คํจ์ ์๊ด์์ด ์ฒ๋ฆฌ๊ฐ ๋๋ ์ํ)๊ฐ ๋์ ๋ resolveํ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ์ฐ๊ด๋์ง ์์ ์ฌ๋ฌ promise๋ฅผ ์ฌ์ฉํด์ผ ํ ๋ ๋ชจ๋ await์ ๋ถ์ฌ์ ์ฌ์ฉํ๋ฉด ์๊ฐ์ด ์ค๋๊ฑธ๋ฆฌ๋ ๋จ์ ์ ๊ฐ๋๋ค. ์์ ์ ๋ฆฌํ Promise.all์ ์ด์ฉํด ๋ณ๋ ฌ ์ฒ๋ฆฌ๋ก ํ๋ฒ๋ง await ์ฌ์ฉํด ํด๊ฒฐ๊ฐ๋ฅํ๋ค.
//์์ ์
async function foo() {
const a = await new Promise(resolve => setTimeout(() => resolve(1), 3000))
const b = await new Promise(resolve => setTimeout(() => resolve(2), 2000))
const c = await new Promise(resolve => setTimeout(() => resolve(3), 1000))
console.log([a, b, c])
}
foo() // 6์ด ๋ค [1,2,3]
async function foo() {
const res = await Promise.all([
new Promise(resolve => setTimeout(() => resolve(1), 3000)),
new Promise(resolve => setTimeout(() => resolve(2), 2000)),
new Promise(resolve => setTimeout(() => resolve(3), 1000)),
])
console.log(res)
}
foo() // 3์ด ๋ค [1,2,3][์ฐธ๊ณ ]
๋ชจ๋ ์๋ฐ์คํฌ๋ฆฝํธ ๋ฅ๋ค์ด๋ธ ์ ๋๋ ์ดํฐ์ async/await