const processData = () => { } console.log(processData()) //undefined
먼저 아무것도 리턴하지 않는 단순한 함수 processData()를 만들어보자. 결과가 undefined로 나온다.
const processData = async () => { } console.log(processData()) //Promise { undefined }
The async function always, always return a promise, that promise is resolved with the value that you the developer choose to return from the function
그렇다면 async를 붙여 아무것도 리턴하지 않는 Async 함수를 만들어보자. 결과는 프로미스 형태로 나온다. Async 함수는 반드시 프로미스를 반환하며, 프로미스의 특징처럼 우리가 원하는 바를 resolve한 결과다.
const processData = async () => { throw new Error('something went wrong...') } processData().then((data) => { console.log('Data', data) //Data 12 }).catch((err) => { console.log('Error', err) //Error something went wrong... })
We now know that a async returns a promise, so we can attach .then() to set up our success handler when the promise resolves the value, .catch() also, when async function rejects
Async 함수가 프로미스를 리턴하기 때문에, 당연히 .then()이나 .catch()를 붙여서 프로미스 체인을 만들 수 있다.
이제 위에서 만든 async 함수를 이용해 await를 어떻게 사용하는지 알아본다. 참고로 await는 async 함수에서만 사용할 수 있는 연산자다.
숫자를 넣으면 형태가 number인지 확인 후 2를 곱하는 간단한 프로미스를 가져왔다.
const getDataPromise = (num) => new Promise((resolve, reject) => { setTimeout(() => { typeof num === 'number' ? resolve(num*2) : reject('Number must be provided') }, 1000) })
위에서 만든 async 함수 안에 await를 사용해서 getDataPromise()를 다시 불러왔다.
const processData = async () => { let data = await getDataPromise(2) data = await getDataPromise(data) //8 data = await getDataPromise(data) //16 return data }
위에서 만든 출력 코드를 그대로 가져왔다.
processData().then((data) => { console.log('Data', data) }).catch((err) => { console.log('Error', err) })
Only be used with async function
Await 연산자는 async 함수에서만 사용할 수 있다.
first line in the function: call function with await operator, pass in arguments it expects.
async 함수 안에서 맨 첫째줄에서 await을 쓰고 함수를 호출한다. 기존 sync 함수 형태처럼, 인자가 필요한 함수면 인자를 집어넣는다.
We used the await operator with a function that RETURNS A PROMISE ... we dont have to attach .then() and set up a callback function
await 연산자를 통해 우리는 프로미스를 반환하는 함수를 가져온다. .then()을 붙일 필요 없이 그냥 await으로 함수를 불러오면 된다.
Previously if we wanted to use a promise multiple times we attached .then(), used promise chaining. We can structure our code that uses promises to look more like regular old sychronous code, we can perform one operation after the other, one operation after another, if either one rejected it wont run.
기존의 프로미스 체인에서는 프로미스를 여러번 연달아서 사용하고 싶을 때 .then()을 줄줄이 붙였지만 Async/Await을 사용하면 일반적인 sync 함수와 비슷한 형태로 함수를 구성하면서도 프로미스의 기능 대로 resolve/reject를 이용할 수 있다.
If one promise rejected, it means throwing an error, so we can catch that err later. we dont need to throw new Error().
중간에 한 개의 await가 reject되면 프로미스체인에서와 마찬가지로 throw error의 의미를 가지며 따라서 그 에러는 나중에 catch하면 된다. 따로 throw new Error()가 필요없다.
프로미스 체인으로 구성했던 함수를 async/await 형태로 변환해 보고 어떤 이점이 있는지 알아본다.
기존 프로미스 체인으로 짠 코드
const getPuzzleOld = (wordCount) => { return fetch(`http://puzzle.mead.io/puzzle?wordCount=${wordCount}`).then((response) => { if (response.status === 200) { return response.json() } else { throw new Error('Unable to fetch puzzle') } }).then((data) => { return data.puzzle //string }) }
async/await 형태로 다시 구성한 코드
const getPuzzle = async (wordCount) => { const response = await fetch(`http://puzzle.mead.io/puzzle?wordCount=${wordCount}`) if (response.status === 200) { const data = await response.json() return data.puzzle } else { throw new Error('unable to get puzzle') } }
위의 getPuzzleOld(), getPuzzle()는 아래와 같은 동일한 방법으로 호출 가능하다.
getPuzzle('2').then((puzzle) => { console.log(puzzle) }).catch((err) => { console.log(`Error: ${err}`) })
Await the fetch to complete, and store that in response, and continue on. no need for .then(), just move on.
Fetch()를 활용하여 데이터를 받아오기까지 기다렸다가, 그 응답을 또 활용하는 방식은 프로미스체인과 똑같은데, 끄트머리에 .then()을 붙이지 않고도 await으로 코드를 정리할 수 있기 때문에 눈에 더 잘 들어온다.
It's typically best to put promise chaining in an async function, allowing us to easily structure the code in a simple familier maintainable way
프로미스체인으로 표현하는 것보다 async 함수로 표현하는 쪽이 훨씬 직관적이고 유지보수에 용이한 형태로 구성할 수 있다.