이번에는 저번 글에서 배웠던 Async에 이어 이와 함께 사용하는 Awiat에 대해 살펴봅시다.
자세한 사항은 꼭 MDN 공식문서 - await을 참고해주시기 바랍니다.
const delayedColorChange = (color, delay) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
document.body.style.backgroundColor = color;
resolve();
}, delay)
})
}
위와 같이 배경색을 입력한 delay
마다 바꿔주는 함수를 Promise
로 구현하였습니다. 위 코드를 async
함수로 호출하는 경우에는 어떻게 할까요?
async function rainbow() {
return delayeColorChange('red', 1000)
}
rainbow()
위처럼 async
함수 내부에 delayeColorChange('red', 1000)
을 통해 Promise
함수 호출을 return
합니다. 그러면 async
함수이므로 Promise
객체의 resolve
값을 반환하고 배경색이 바뀌게 됩니다. 그렇다면 이를 여러번 반복하여 시간순서대로 배경색이 바뀌게 하려면 어떻게 하면 될까요?
이런 경우에 바로 awiat
키워드가 사용됩니다.
async function rainbow() {
await delayedColorChange('red', 1000)
return delayedColorChange('orange', 1000)
}
async function rainbow() {
await delayedColorChange('red', 1000)
await delayedColorChange('orange', 1000)
await delayedColorChange('yellow', 1000)
await delayedColorChange('green', 1000)
await delayedColorChange('blue', 1000)
await delayedColorChange('purple', 1000)
}
위와 같이 await
키워드를 활용해 무지개색으로 순서대로 변화하는 코드도 nesting 없이도 쉽게 함수를 연결할 수 있게 되었습니다.
async
함수에는await
식이 포함될 수 있습니다. 이 식은async
함수의 실행을 일시 중지하고 전달된Promise
의 해결을 기다린 다음async
함수의 실행을 다시 시작하고 완료 후 값을 반환합니다.
async
함수를 호출 시, then
속성을 덧붙일 수도 있습니다.
async function rainbow() {
await delayedColorChange('red', 1000)
await delayedColorChange('orange', 1000)
await delayedColorChange('yellow', 1000)
await delayedColorChange('green', 1000)
await delayedColorChange('blue', 1000)
await delayedColorChange('violet', 1000)
return console.log("ALL DONE!")
}
rainbow().then(() => { console.log('END OF RAINBOW!') })
위에서 호출한 rainbow
에 then
속성을 붙이면, 배경색이 모두 바뀌고 ALL DONE!이 콘솔에 출력된다음 then
속성에 콜백 함수로 정의한 END OF RAINBOW!가 콘솔에 출력됩니다.
그렇다면, async
함수 내부에 async
함수를 호출할 수 있을까요?
async function printRainbow() {
await rainbow() // Promise가 resolve 될 때까지 기다림
console.log('END OF RAINBOW!')
}
printRainbow()
위 함수처럼 가능하며, await
키워드도 활용이 가능합니다. then
속성으로 구현한 코드와 동일하게 실행됩니다.
하지만 아직까지 async
함수를 통해 Promise
가 rejected
의 경우, 어떻게 해결해야하는지 알지 못했습니다.
try {
asdfsaf.log('asdf') // ReferenceError
} catch (e) {
console.log('ITS OK!!', e) // try 무시한 후 catch 실행! e는 에러 내용 출력
}
여기서 try
, catch
가 사용됩니다. 위에서 보이는 것처럼 try
는 값에 에러가 들어간다하더라도 뒤에 이어지는 catch
에서 이를 무시하고 실행하게 됩니다. 또한, catch
의 매개변수는 try
의 에러 내용을 출력합니다.
const fakeRequest = (url) => {
return new Promise((resolve, reject) => {
const delay = Math.floor(Math.random() * (4500)) + 500;
setTimeout(() => {
if (delay > 4000) {
reject('Connection Timeout :(')
} else {
resolve(`Here is your fake data from ${url}`)
}
}, delay)
})
}
이전 시간에 만들었던 fakeRequest
코드를 통해 try
, catch
를 활용해봅시다.
async function makeTwoRequest() {
try {
let data1 = await fakeRequest('/page1')
let data1 = await fakeRequest('/page2')
console.log(data1)
} catch (e) {
console.log('CAUGHT AN ERROR!')
console.log('error is:', e)
}
}
async
함수로 호출을 했습니다. 에러가 발생했다면, 실제로 에러가 발생하고 이후에 내용은 실행되지 않습니다. 하지만 아래에서 보여드리는 내용처럼 에러가 발생하고 난 후에 catch
의 내용이 실행된 것을 확인할 수 있습니다.