- async/await는 프로미스를 기반으로 동작합니다.
- 비동기 처리 결과를 후속 처리 없이 마지 동기 처리처럼 프로미스를 사용할 수 있습니다.
- 프로미스의 후속 처리 메서드 없이 마치 동기 처리처럼 프로미스가 처리 결과를 반환하도록 구현할 수 있다.
const getRequestDataUseFetch = async() => {
const url = "https://jsonplaceholder.typicode.com/comments/1"
const response = await fetch(url);
const comments = await response.json()
console.log(comments)
}
getRequestDataUseFetch()
Async 함수
- await 키워드는 반드시 async 함수 내부에서 사용해야 한다. async 함수는 async 키워드를 사용해 정의하며 언제나 프로미스를 반환한다.
- async 함수가 명시적으로 프로미스를 반환하지 않더라도 async 함수는 암묵적으로 반환값을 resolve하는 프로미스를 반환한다.
const foo = async(n) => {return n}
foo(1).then(res => console.log(res))
async function bar(n) {
return n;
}
bar(2).then(function(n){console.log(n)})
const baz = async function(n) {return n}
baz(3).then(function(n){console.log(n)})
const obj = {
async foo(n) {
return n
}
}
obj.foo(4).then(res => console.log(res))
class AsyncClass {
async getPromise (n) {
return n
}
}
const getNumber = new AsyncClass()
getNumber.getPromise(5).then(res => console.log(res))
- 단, 클래스의 constructor 메소드는 async 메서드가 될 수 없다. 클래스의 constructor 메소드는 인스턴스를 반환해야 하지만 async 함수는 언제나 프로미스를 반환해야 한다.
class AsyncClass {
async constructor() {
}
}
const getClass = new AsyncClass();
await 키워드
- await 키워드는 프로미스가 settled 상태(비동기 처리가 수행된 상태)가 될 때까지 대기하다가 settled 상태가 되면 프로미스가 resolve한 처리 결과를 반환한다.
- await 키워드는 반드시 프로미스 앞에서 사용해야 한다.
const getTodosData = async(id) => {
const url = `https://jsonplaceholder.typicode.com/todos/${id}`
const response = await fetch(url); "1번"
const todoData = await response.json(); "2번"
console.log(todoData)
}
getTodosData(5)
- await 키워드는 프로미스가 settled 상태가 될 때까지 대기
- 1번의 함수가 수행한 HTTP 요청에 대한 서버의 응답이 도착해서
- fetch 함수가 반환한 프로미스가 settled 상태가 될 때까지 1번에서 대기.
- 이후 프로미스가 settled 상태가 되면 프로미스가 resolve한 처리 결과가 response 결과에 할당된다.
- 이 처럼 await 키워드는 다음 실행을 일시 중단 시켰다가 프로미스가 settled상태가 되면 다시 재개한다.
const getTimerData = async() => {
const one = await new Promise(
(res) => setTimeout(() => {return res(10)},3000)
)
console.log(one)
const two = await new Promise(
(res) => setTimeout(() => {return res(20)}, 2000)
)
console.log(two)
const three = await new Promise(
(res) => setTimeout(() => {return res(30)}, 1000)
)
console.log(three);
console.log([one,two,three])
}
* one 상수에서 동작하는 프로미스 객체가 값을 리턴하여 one 상수에 할당 되기까지 하위 코드는 멈춤
* 상수 one에 3초뒤 10이 할당되면 다음 코드로 넘어가서 콘솔 동작
* 상수 two에서 동작하는 프로미스 객체가 값을 리턴하여 two 상수에 할당 되기까지 하위 코드 멈춤
* 상수 two에 2초뒤 20이 할당되면 하위 코드로 넘어가 콘솔 동작
* 상수 three에서 동작하는 프로미스 객체가 값을 리턴하여 three 상수에 할당 되기까지 하위코드 멈춤
* 상수 three에 1초뒤 30이 할당되면 하위코드로 넘어가 콘솔 동작
* console.log([one,two,three])
- 모든 프로미스에 await 키워드를 사용하는 것은 주의해야한다.
- getTimerData 함수가 수행하는 3개의 비동기 처리는 서로 연관이 없이 개별적으로 수행되는 비동기 처리 이므로 앞선 비동기 처리가 완료될 때까지 대기해서 순차적으로 처리할 필요는 없다.
- 아래와 같이 개선하면 좋다.
const getTimerData = async() => {
const res = await Promise.all([
new Promise(resolve => setTimeout(() => {return resolve(10)},3000)),
new Promise(resolve => setTimeout(() => {return resolve(20)},2000)),
new Promise(resolve => setTimeout(() => {return resolve(30)},1000))
])
console.log(res)
}
getTimerData()
- 다음 예제는 앞선 비동기 처리의 결과를 가지고 다음 비동기를 처리해야한다. 따라서 비동기 처리의 처리 순서가 보장되어야 하므로 모든 프로미스에 await 키워드를 써서 순차적으로 처리해야한다.
const bar = async(n) => {
const one = await new Promise(
(res) => setTimeout(() => {return res(n)},3000)
)
const two = await new Promise(
(res) => setTimeout(() => {return res(one + 1)},2000)
)
const three = await new Promise(
(res) => setTimeout(() => {return res(two + 1)},1000)
)
console.log([one, two, three])
}
bar(10)
에러 처리
- 비동기 처리를 위한 콜백 패턴의 단점 중 가장 심각한 것은 에러 처리가 곤란하다는 것.
- async/await 에서 에러처리는 try…catch 문을 사용할 수 있다.
const getData = async() => {
try{
const wrongUrl = "https://jsonplaceholder.typicode.comXXXXX/todos/1";
const response = await fetch(wrongUrl)
const data = await response.json()
console.log(data)
}catch(e) {
console.log("Error!" , e)
}
}
getData()
- 위 예제의 getData 함수의 catch 문은 HTTP 통신에서 발생한 네트워크 에러뿐만 아니라 try 코드 블록 내의 모든 문에서 발생한 일반적인 에러까지 모두 캐치할 수 있다.
- async 함수 내에서 catch 문을 사용해서 에러 처리를 하지 않으면 async함수는 발생한 에러를 reject하는 프로미스를 반환한다.
- 따라서, async 함수를 호출하고 Promise.prototype.catch 후속 처리 메서드를 사용하여 에러를 캐치할 수 있다.
const getData = async() => {
const wrongUrl = "https://jsonplaceholder.typicode.comXXXXX/todos/1";
const response = await fetch(wrongUrl)
const data = await response.json()
return data
}
getData()
.then((res) => console.log(res))
.catch((e) => console.log("Error !", e))
끄적끄적..
const get = async(n) => {
try{
const res = await Promise.allSettled([
new Promise (res => {
const ret = fetch(`https://jsonplaceholder.typicode.com/comments/${n}`)
ret.then((res) => res.json()).then((res) => console.log(res))
res(1)
}
),
new Promise (res => {
const ret = fetch(`https://jsonplaceholder.typicode.com/photos/${n}`)
ret.then((res) => res.json()).then((res) => console.log(res))
res(2)
}
),
new Promise (res => {
const ret = fetch(`https://jsonplaceholder.typicode.com/todos/${n}`)
ret.then((res) => res.json()).then((res) => console.log(res))
res(3)
}
)
])
return res
}catch(e) {
console.log("Error" , e)
}
}
get(1).then((res) => console.log(res))