Java, JavaScript/Node

[Node] 비동기 처리 - async/await

FiveReptile 2021. 10. 14. 10:07
728x90

Promise를 사용하여 콜백 함수의 늪에서는 빠져나올 수 있었지만 Promise도 마찬가지로 reject와 resolve 그리고 .then, .catch들을 사용하면서 눈으로 보기에 코드가 완전히 깔끔하지 않습니다. 이때 async/await를 사용하면 앞에서 나열한 함수들을 사용하지 않고 코드를 깔끔하게 유지할 수 있습니다. 또한 비동기로 진행되는 Promise를 구조적으로 동기로 진행되는 것처럼 해줍니다. 그 이유는 다음과 같습니다.

 

Async functions can contain zero or more await expressions. Await expressions make promise-returning functions behave as though they're synchronous by suspending execution until the returned promise is fulfilled or rejected. The resolved value of the promise is treated as the return value of the await expression. Use of async and await enables the use of ordinary try / catch blocks around asynchronous code.
출처: MDN Web Docs (링크)

 

다시말해 "async 함수 내에서는 await 키워드를 사용할 수 있습니다. await 키워드는 전달 된 Promise의 결과가 반환될 때까지 async 함수의 실행을 일시적으로 중지시킵니다. async/await에서 try / catch 구문을 사용할 수 있습니다" 라고 말할 수 있습니다.

 

이유를 정리하자면 async 함수 내에 있는 Promise들은 await 키워드에 의해 Promise를 실행할 때 남은 코드들이 기다리기 것 입니다.

 

다음은 setTimeout을 사용한 async/await 예제입니다.

 

function resolveAfter2Seconds() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('2초 후 성공');
        }, 2000);
    });
}

 

2초 후에 "2초 후 성공"을 반환하는 Promise 코드입니다.

 

async function asyncCallSetTimeout() {
    try {
        console.log('시작');
        const result = await resolveAfter2Seconds();
        console.log(result);
        console.log('끝');
    } catch (e) {
        console.log(e);
    }
}
asyncCallSetTimeout();

 

async/await는 다음과 같이 사용합니다. function 앞에 async를 선언해주고, Promise를 반환하는 함수 앞에 await를 선언합니다. 위의 코드의 실행 결과는 다음과 같습니다.

 

시작
2초 후 응답
끝

 

앞서 설명했던 것처럼 await 키워드를 사용한 Promise의 결과를 반환할 때까지 기다린 후에 결괏값인 "2초 후 응답"과 마지막 출력문인 "끝"이 출력된 것을 확인할 수 있습니다. async/await를 사용하지 않은 결과는 다음과 같습니다.

 

시작
끝
2초 후 응답

 

단순한 출력문이라서 언듯 보기에 문제가 없을 것 처럼 보일 수도 있지만 Promise의 연산 결과가 후의 코드에 영향을 주는 것이라면 코드가 정상적으로 동작하지 않을 수 있습니다. 따라서 Promise의 연산 결과가 중요한 함수일 경우에 async/await를 사용하는 것을 고려해볼 수 있습니다.

 

다음은 2개의 Promise를 사용한 async/await 코드입니다.

 

function promise1() {
    return new Promise((resolve, reject) => {
        resolve('바로 성공');
    });
}

function promise2() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('1초 후 성공');
        }, 1000);
    });
}

 

 promise1의 실행 즉시 "바로 성공을 반환합니다" promise2는 실행 후 1초 뒤에 "1초 후 성공"을 반환합니다. 다음은 async/await 실행 코드입니다.

 

async function promiseMultiple() {
    try {
        console.log("시작");
        const result1 = await promise1();
        console.log(result1);

        const result2 = await promise2();
        console.log(result2);
        console.log("끝");
    } catch (e) {
        console.error(e);
    }
}
promiseMultiple();

 

promise1과 promise2가 순차적으로 실행되고 코드의 시작과 끝에 "시작"과 "끝"이라는 출력문을 추가해주었습니다. 그리고 promise1과 promise2는 catch 처리를 안 해주었으므로 async 함수에서 try / catch 구문을 사용하여 error를 처리해줍니다. 코드의 실행 결과는 다음과 같습니다.

 

시작
바로 성공
1초 후 성공
끝

 

코드의 순서에 맞게 결과가 출력되는 것을 확인할 수 있습니다.

728x90