별코딩 JavaScript - Async & Await

clouood·2024년 2월 9일

별코딩

목록 보기
6/6

Async & Await은 프로미스를 한 단계 감싸서 보기 편하게 만들어주는 문법! 전혀 새로운 방식이 아님. 프로미스를 배울 때, 'promise chaining' 방식으로 여러가지 비동기 작업을 순차적으로 수행할 수 있었음. Async & Await을 사용하면 그러한 복잡한 chaining 없이, 동기적인 코드를 작성하듯 훨씬 간편하게 코드를 작성할 수 있다.


Async

Async는 비동기 함수를 정의할 때 사용하는 키워드. 함수를 만들 때 사용하는 function 키워드 앞에다가 붙여주기. -> 비동기 함수가 됨. 그렇다면 이 함수와 일반 함수는 어떤 차이가 있을까?

일반 함수 ↑
반환된 값을 가지는 user를 console.log로 출력해보면,

잘 출력됨.


이번엔 Async를 붙인 함수를 사용해보자.
Async를 붙여주면 이 함수는 항상 프로미스를 리턴하는 '비동기 함수'가 됨.

이제 '개발자 LEE'라는 문자열이 도출되는 것이 아니라 프로미스 객체가 콘솔에 출력됨. 프로미스가 가지는 result는 함수 안에서 리턴해준 '개발자 LEE'임.

async가 붙은 함수는 항상 프로미스 반환!

함수 안에서 어떤 값을 리턴해주면 그 값은 프로미스로 감싸져서 반환됨. 그렇기에 getUser로부터 반환된 user는 프로미스가 됨. 출력해보면 프로미스 출력. 이제 '개발자 LEE'라는 문자열에 접근하기 위해서는 프로미스에 'then'을 사용하면 됨.

잘 출력됨.

만약에 Async가 붙은 함수 안에서 문자열 등의 값이 아니라 프로미스를 직접적으로 리턴하면 어떻게 될까? 위에 프로미스 하나 만들어보기.

프로미스를 직접적으로 반환하면, 프로미스를 프로미스가 한 번 더 감쌀까? 그건 아님. Async가 붙은 함수는 항상 프로미스가 반환되도록 되어있으나, 직접적으로 프로미스를 리턴하는 경우는 프로미스가 그대로 반환됨. user에 그대로 들어가게 되는 것임.

잘 출력됨.

함수 앞에 Async를 붙이면 항상 프로미스를 반환하는 비동기 함수가 됨!

getUser가 비동기 작업을 수행하도록 만들어보자.
이 함수는 네트워크 요청을 해서 서버로부터 사용자 이름을 받아오는 일을 한다고 가정해보자. 함수를 하나 만들자.


networkRequest 함수는 그냥 네트워크 요청에 2초가 걸린다는 것을 흉내내는 함수임. 함수를 호출하고 2초 뒤 '데이터를 받아왔습니다.'가 출력될 것임.

'개발자 LEE'가 먼저 출력되고, '데이터를 받아왔습니다.'가 출력됨. 내가 원하는 것은 반대임. 왜 이렇게 출력되냐면 networkRequest가 끝나는 것을 기다려 주지 않아서 그럼. networkRequest는 비동기적으로 수행되기 때문에 끝날 때까지 기다리지 않고 바로 다음 줄로 넘어가서, '개발자 LEE'가 출력된 것임. getUser가 정상적으로 작동하기 위해서는, networkRequest가 끝날 때까지 잠시 멈춰 기다렸다가 그다음 '개발자 LEE'를 리턴해줘야 함. 이럴 때 사용하는 것이 'Await'.

Await

networkRequest 앞에 'await'을 붙여주면 networkRequest가 끝날 때까지 함수의 진행을 잠시 멈춰서 기다렸다가 다 끝나고 나면 '개발자 LEE'를 리턴함.

2초 뒤 잘 출력.


이처럼 Async 함수 안에서 어떤 비동기 함수가 완료되길 기다려야 한다면 'await'을 붙여주면 됨! 'Await' 키워드는 프로미스가 완료될 때까지 기다려주는 역할을 함. networkRequest는 2초 뒤에 완료되는 프로미스를 리턴함. 앞에 await을 붙여주면 프로미스가 끝날 때까지 잠시 멈춰서 기다려줄 수 있음. 만약에 프로미스가 어떤 값으로 resolve가 된다면, 변수 안에다 값을 넣을 수 있음.

서버 1 잘 출력.


만약 Async 함수 안에서 여러 개의 비동기 함수를 순차적으로 실행해주고 싶다면, await을 여러 번 사용하면 됨.

2초, 2초 해서 4초 뒤에 '개발자 LEE'가 출력됨.


이처럼 Async와 Await을 사용하면 비동기 작업을 마치 동기적으로 수행하듯이 코드를 짤 수 있다. 프로미스 개념에서는 여러 개의 비동기 작업을 순차적으로 처리해주기 위해서 promise chaining을 사용했음. 이를 사용하는 것보다 Async와 Await을 사용하면 훨씬 가독성이 높은 코드를 작성할 수 있음. 그래도 연습해야 하니까 이 작업을 promise chaining으로 바꿔보자.

Async Await을 사용한 버전과 promise chaining을 사용한 버전을 비교해보면 확실히 Async Await을 사용한 버전이 가독성이 좋다.

[주의사항]

'Await' 키워드는 반드시 Async 키워드가 붙은 함수 내부에서만 사용 가능하다. 만약, Async 함수 외부에서 사용하게 되면 어떻게 될까? 에러 발생.

Await은 Async 함수 내부에서만 사용할 수 있다는 에러 메시지.

↑ 새로운 함수를 만들어줬음.

& getUser와 getTodo 두 가지 함수를 호출하는 또다른 비동기 함수를 만들어보자.

2초 뒤 출력.


await은 프로미스가 완료되길 기다리는 일을 함. getUser는 async 키워드가 붙은 비동기 함수이기 때문에 프로미스를 반환함. await은 getUser가 반환한 프로미스가 완료될 때까지 기다림. getUser 함수를 살펴보면 networkRequest가 끝나길 2초 동안 기다렸다가 '개발자 LEE'를 리턴하면서 프로미스가 완료되기 때문에, const user = await getUser();는 2초 동안 getUser가 완료되길 멈춰서 기다렸다가 다 완료되면 '개발자 LEE'를 전달 받고 그 다음 줄로 넘어가서 conosle.log가 수행되는 것임.


변수를 하나 더 만듦. todo. await getTodo()에서 2초 기다렸다가 getTodo가 완료되면 '축구 시청'과 '밥 먹기'가 들어있는 배열을 전달 받고 그 다음 줄로 넘어가서 console.log가 수행됨.


에러처리

Async 안에서 에러처리하는 법?
일반 함수에서 하는 것처럼 똑같이 하면 됨.
try, catch문 사용하기.


그럼 getUser에서 에러가 발생하도록 만들어보자.

에러메시지 출력.


에러가 발생할 수 있는 부분을 try catch로 감싸주면 됨.
const를 let으로 바꿔준 다음, 에러가 발생할 수 있는 코드를 try 안에 넣고, 에러가 잡히면 에러 메시지를 출력해주도록 코드를 짜보자.

undefined 출력.


Fetch API

Fetch API를 사용할 비동기 함수를 하나 만들어보자.

response 객체가 출력됨.
이제 response에서 받아온 데이터를 추출해주기 위해서는 response 객체에 json 메서드를 사용하면 됨. json 메서드 또한 프로미스를 반환하기 때문에 await을 사용할 수 있음.

10개의 사용자 데이터가 출력되었음.

profile
雲外蒼天

0개의 댓글