async/await

jaeung5169·2021년 8월 19일
0

JavaScript

목록 보기
16/17
post-thumbnail

callback 패턴의 여러 단점을 해결한 Promise 또한 결과적으로는 비동기 처리이므로, 동기식 코드와 섞어서 사용하면 코드의 흐름을 파악하기 어렵다는 단점이 있다.

하지만 ES 2017(ES8)에서 추가된 async/await 키워드를 사용하면 비동기 처리도 동기식 흐름처럼 보이게 할 수 있다.

두 키워드가 어떤 기능을 하는지 예제를 통해 자세히 알아보자!😆



async

async 키워드는 함수 앞에 붙일 수 있는 키워드이다. 일반적인 함수는 물론이고 익명 함수의 앞에도 사용할 수 있다.

함수의 앞에 async 키워드를 붙이게 되면, 해당 함수가 반환하는 값은 항상 Promise 객체가 된다.

무슨 의미인지 아래 예제를 보도록 하자!


const func = async function() {
    return 'Im function';
};

console.log(func()); // Promise { 'Im function' }
func().then(str => console.log(str)); // Im function

func() 함수를 호출한 결과 문자열 'Im function' 을 반환하는 것이 아니라, Promise.resolve('Im function') 으로 fulfilled 상태가 된 Promise 객체를 반환하는 것을 볼 수 있다.

이렇게 async 키워드를 사용하면 기본형 데이터를 반환하더라도 Promise 객체로 래핑해서 반환한다는 것을 알 수 있다.

그럼 이 기능을 어디에다 써먹느냐. 바로 async 키워드를 사용한 함수는 내부에서 await 키워드를 사용할 수 있다. 는 점이다.





await

async/await 키워드를 묶어서 설명하는 이유는, await 키워드는 단독으로 사용할 수 없고 반드시 async 키워드가 붙은 함수 내부에서만 사용할 수 있기 때문이다.

또한 await 키워드는 Promise 객체를 반환하는 함수 에만 사용할 수 있으므로, Promise 객체를 정확히 이해하는 것이 선행된다.

그럼 await 키워드는 어떤 역할을 하는지 예제를 통해 알아보자!🙃


delayPrint();

function delayPrint() {
    let str = 'string';

    const promise = new Promise((resolve, reject) => {
        setTimeout(() => resolve('async data!'), 2000);
    });

    promise.then(data => str = data);
    console.log(str); // 'string'
}

Promise 역시 비동기 처리이므로 delayPrint() 함수를 호출한 결과는 동기식 코드가 먼저 처리된다.

따라서 then() 메서드를 이용해 str = 'async data!' 를 실행하고 console.log() 함수로 출력해주려고 했지만, 원하는 결과를 얻을 수 없다.

위 코드를 async/await를 활용한 코드로 바꾸면 어떻게 되는지 보도록 하자!


delayPrint();

async function delayPrint() {
    let str = 'string';

    const promise = new Promise((resolve, reject) => {
        setTimeout(() => resolve('async data!'), 2000);
    });

    str = await promise;
    console.log(str); // 'async data!'
}

놀랍게도 동기식 코드와 비동기식 코드가 섞여 있는데도 불구하고 정상적으로 동작한다!😨

이유는 await 키워드가 붙여진 Promisesettled 되기 전까지 다음 코드를 실행하지 않고 기다리기 때문이다.

'그럼 동기식 코드와 다를 바 없는 것이 아닌가?' 라고 생각할 수 있지만, await 키워드를 이용해 대기하고 있는 Promise는 여전히 비동기 처리이기 때문에, 메인 스레드가 멈추는 걱정을 하지 않아도 된다.

이 말이 사실인지 delayPrint() 함수를 호출하기 전후로 동기식 코드를 추가해보자!


console.log('Im outer code! before delayPrint()');
delayPrint();
console.log('Im outer code! after delayPrint()');

async function delayPrint() {
    let str = 'string';

    const promise = new Promise((resolve, reject) => {
        setTimeout(() => resolve('async data!'), 2000);
    });

    str = await promise;
    console.log(str);
}

실행 결과
1. Im outer code! before delayPrint()
2. Im outer code! after delayPrint()
3. delay 2s
4. async data!


delayPrint() 함수는 정확히 비동기식으로 실행되며, 함수 내부에서는 동기식 흐름을 가진다는 것을 알 수 있다.

그리고 await 키워드를 사용해서 동기식 프로그램처럼 만들면, 예외 처리도 손쉽게 가능하다는것 또한 장점이다.



async/await의 에러 핸들링

Promisecatch() 메서드를 이용해서 에러에 대한 처리를 진행했다.

하지만 async/await를 사용하면 비동기 코드에서도 마치 동기식 코드처럼 try...catch 문법을 이용해서 에러 핸들링이 가능하다!

파일을 불러오는 함수를 async/await를 사용해서 작성해보자.


const fs = require('fs');

getFileContent()

async function getFileContent() {
    let str = 'original';

    const promise = new Promise((resolve, reject) => {
        fs.readFile('./text_1.txt', (err, data) => {
            if(err) return reject(err);
            else if(data.toString() === '') return reject('no contents');
            resolve(data.toString());
        });
    });

    try {
        str = await promise;
        console.log(str);
    } catch(err) {
        console.error(err);
    }
}

async/await 키워드를 사용하면 위의 코드처럼 비동기 코드에서도 try ... catch 문법을 이용해서 훨씬 이해하기 쉬운 에러 처리가 가능해진다.

이처럼 async/await 키워드는 callback 패턴 혹은 Promise 패턴만 사용했을 때 보다 훨씬 사람이 읽기 쉬운 코드를 만들 수 있도록 도와주지만, 늘 그렇듯 구형 브라우저에서는 지원하지 않는 경우가 있다.

사용하기 전에 async/await를 지원하는 브라우저인지 꼭 확인하고, 만약 그렇지 않다면 Babel 같은 트랜스파일러를 이용하도록 하자!



모자란 부분이나 틀린 내용이 있다면 지적해주시면 감사하겠습니다!!🙂





참고 자료
async와 await를 사용하여 비동기.. | MDN
https://developer.mozilla.org/ko/docs/Learn/JavaScript/Asynchronous/Async_await


async function | MDN
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/async_function


await | MDN
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/await


async와 await
https://ko.javascript.info/async-await

0개의 댓글