이 번 회차에서는 프로젝트에서 필자가 직접 개발하던 도중에
적용한 비동기 통신 기능 중 ES7에서 새로 나온 기능 중 하나인 async / await에 대해 다룰 것 이다.
난 비동기 통신을 사용하여
input 값 null value check를 성공적으로 완료
->
POST fetch를 통해 파일 업로드가 성공적으로 완료
->
POST fetch를 통해 파일 업로드가 완료된 경로와
그 파일에 대한 정보를 DB에 INSERT 하는 함수를 개발하는 파트에 사용하였다.
잡언은 여기서 각설하고 async / await와 비동기통신에 대해 설명하겠다.
async / await 그리고 비동기 통신이란?
자바스크립트는 싱글 스레드 프로그래밍언어기 때문에 비동기처리가 필수적이다.
비동기 처리는 그 결과가 언제 반환될지 알수 없기 때문에 동기식으로 처리하는 기법들이 사용되어야 하는데,
대표적으로 setTimeout이 있고 callback과 promise가 있다.
세 가지 모두 비동기 코드를 동기식으로 작성하는데 훌륭한 기법들이지만, 모두 약간의 문제점을 가지고 있다.
문제점이 있는 세 가지 비동기 코드 중 가장 큰 문제를 다루자면,
callback은 콜백지옥, promise는 체이닝에서 문제가 발생된다.
async 와 await 는 이런 문제들을 해결함과 동시에 그 사용법에 있어서도 훨씬 단순해졌다.
Promise 문법
function Test() {
return new Promise((resolve, reject) => {
resolve('HI');
// or reject(new Error('error');
});
}
Test().then((result) => console.log(result));
async 문법
async function Test(){
return 'HI';
}
Test().then((result) => console.log(result));
한눈에 봐도 매우 직관적인 코드로 변했다고 느낄수 있다.
함수에 async만 붙이면 자동 Promise객체로 인식되고 return값은 resolve()값과 똑같다.
** reject는 throw 에러를 날리면 된다.
물론 Promise메서드를 줘도 된다.
async function test(){
//return 'hi';
return Promise.resolve('hi');
// return Promise.reject('hi);
}
resolve와 reject는 Promise와 기능이 동일하다.
async 와 await 는 절차적 언어에서 작성하는 코드와 같이 사용법도 간단하고 이해하기도 쉽다.
function 키워드 앞에 async만 붙여주면 되고
비동기로 처리되는 부분 앞에 await만 붙여주면 된다.
- async가 붙은 함수는 프라미스를 반환하고, 프라미스가 아닌 것은 프라미스로 감싸 반환한다.
- await 키워드를 만나면 프라미스가 처리(settled)될 때까지 기다린다.
그리고 프라미스가 처리가 완료되어 resolve(값) 되면 값만 따로 추출해서 리턴한다.
await는 promise.then보다 좀 더 세련되게 프라미스의 result 값을 얻을 수 있도록 해주는 문법이다.
promise.then보다 가독성 좋고 쓰기도 쉽다.
** TIP |
async/await가 Promise를 완벽히 대체하는 것이 아니다. 비동기는 Promise객체로 처리하고 async/await는 비동기를 동기식으로 처리하는 기법이다. 기존에는 Promise에 직접 .then()을 통해 동기처리를 했지만, await를 사용하면 바로 동기처리가 되기 때문이다. |
async/await와 promise.then
async/await을 사용하면 await가 대기를 처리해주기 때문에 .then이 거의 필요하지 않는다.
여기에 더하여 promise.catch 대신 일반 try..catch를 사용할 수 있다는 장점도 생긴다.
항상 그러한 것은 아니지만, promise.then을 사용하는 것보다 async/await를 사용하는 것이 대개는 더 편리하다.
그런데 문법 제약 때문에 async함수 바깥의 최상위 레벨 코드에선 await를 사용할 수 없다.
그렇기 때문에 관행처럼 .then/catch를 추가해 최종 결과나 처리되지 못한 에러를 다룬다.
에러 핸들링
프라미스가 정상적으로 이행되면 await promise는 프라미스 객체의 result에 저장된 값을 반환한다.
반면 프라미스가 거부되면 마치 throw문을 작성한 것처럼 에러가 던져진다.
EX)
async function test() {
await Promise.reject(new Error("ERROR"));
}
위 코드는 아래 코드와 동일하다.
async function test() {
throw new Error("ERROR");
}
실제 상황에선 프라미스가 거부 되기 전에 약간의 시간이 지체되는 경우가 있다.
이런 경우엔 await가 에러를 던지기 전에 지연이 발생한다.
await가 던진 에러는 throw가 던진 에러를 잡을 때처럼 try..catch를 사용해 잡을 수 있다.
async function test() {
try {
let response = await fetch('http://유효하지-않은-주소');
} catch(err) {
console.log(err); // TypeError: failed to fetch
}
}
test();
에러가 발생하면 제어 흐름이 catch 블록으로 넘어간다.
여러 줄의 코드를 try로 감싸는 것도 가능하다.
async function test() {
try {
let response = await fetch('http://유효하지-않은-주소');
let user = await response.json();
} catch(err) {
// fetch와 response.json에서 발행한 에러 모두를 여기서 잡는다.
console.log(err);
}
}
test();
try..catch가 없으면 아래 예시의 async 함수 f()를 호출해 만든 프라미스가 거부 상태가 된다.
test()에 .catch를 추가하면 거부된 프라미스를 처리할 수 있다.
async function test() {
let response = await fetch('http://유효하지-않은-주소');
}
// test()는 거부 상태의 프라미스
test().catch(alert); // TypeError: failed to fetch // (*)
.catch를 추가하는 걸 잊으면 처리되지 않은 프라미스 에러가 발생한다.
이런 에러는 프라미스와 에러 핸들링 챕터에서 설명한 전역 이벤트 핸들러 unhandledrejection을 사용해 잡을 수 있다.
요약
function 앞에 async 키워드를 추가하면 두 가지 효과가 있다.
- 함수는 언제나 프라미스를 반환합니다.
- 함수 안에서 await를 사용할 수 있습니다.
프라미스 앞에 await 키워드를 붙이면 자바스크립트는 프라미스가 처리될 때까지 대기한다.
처리가 완료되면 조건에 따라 아래와 같은 동작이 이어진다.
- 에러 발생 – 예외가 생성됨(에러가 발생한 장소에서 throw error를 호출한 것과 동일함)
- 에러 미발생 – 프라미스 객체의 result 값을 반환
async/await를 함께 사용하면 읽고, 쓰기 쉬운 비동기 코드를 작성할 수 있다.
async/await를 사용하면 promise.then/catch가 거의 필요 없다.
하지만 가끔 가장 바깥 스코프에서 비동기 처리가 필요할 때같이 promise.then/catch를 써야만 하는 경우가 생기기 때문에 async/await가 프라미스를 기반으로 한다는 사실을 알고 있어야 한다.
여러 작업이 있고, 이 작업들이 모두 완료될 때까지 기다리려면 Promise.all을 활용할 수 있다는 점도 알고있으면 좋다.
출처:https://ko.javascript.info/async-await
https://inpa.tistory.com/entry/JS-📚-비동기처리-async-await
'자바스크립트 - Vanilla JS' 카테고리의 다른 글
[자바스크립트 / Vanilla JS] 스코프(Scope) (0) | 2022.08.17 |
---|---|
[자바스크립트 / Vanilla JS] 함수 선언식 과 함수 표현식 (0) | 2022.08.01 |
[자바스크립트 / Vanilla JS] new 연산자와 생성자 함수 (0) | 2022.07.20 |
[자바스크립트 / Vanilla JS] window.onload 여러 번 사용하기 (1) | 2022.07.13 |
[자바스크립트 / Vanilla JS] 비공개 멤버 (0) | 2022.07.04 |