[Javascript] async & await

Sungjin·2022년 12월 12일
0

Javascript

목록 보기
1/2

🌈 async & await 란?

async와 await는 자바스크립트의 비동기 처리 패턴 중 가장 최근에 나온 문법이다.

기존의 비동기 처리 방식인 콜백 함수와 프로미스의 단점을 보완하고 개발자가 읽기 좋은 코드를 작성할 수 있게 도와 준다.

🌈 개발자에게 읽기 좋은 코드란?

마치 책이라도 읽듯이 위에서 부터 아래로 차근 차근 읽으면서 사고할 수 있는 그런 코드라고 생각된다.

예를 들어,

var user = {
    id : 1,
    name : "Hong" 
};
if(user.id === 1) {
    console.log(`name = ${user.name}`); // name = Hong
}

와 같은 코드를 말할 수 있다.

🌈 Simple Example

다음의 코드를 보도록 하자.

function logFetchUser(findId) {
    var user = fetchUser(`/api/users/${findId}`); //http 통신 코드라 가정
    if(isUser(user.id, findId))
        console.log(user.name);
}

function isUser(userId, findId) {
    if(userId === findId)
        return true;
    return false;
}

fetchUser() 라는 메서드를 호출하면 HTTP 통신을 통해 서버에서 사용자 정보를 가져온다고 가정한다.

여기서 아래와 같이 asyncawait를 추가해 보자.

async function logFetchUser(findId) {
    var user = await fetchUser(`/api/users/${findId}`);
    if(isUser(user.id, findId))
        console.log(user.name);
}

function isUser(userId, findId) {
    if(userId === findId)
        return true;
    return false;
}

이런 방식으로 asyncawait 를 추가할 수 있다.

이제부터 살펴보도록하자.

🌈 async & await 가 적용된 코드와 그렇지 않은 코드의 차이점

위에서 본 코드를 먼저 살펴보자.

function logFetchUser(findId) {
    var user = fetchUser(`/api/users/${findId}`); //http 통신 코드라 가정
    if(isUser(user.id, findId))
        console.log(user.name);
}

function isUser(userId, findId) {
    if(userId === findId)
        return true;
    return false;
}

fetchUser 는 서버에서 데이터를 받아오는 HTTP 통신 코드라고 가정하였다.

일반적으로 HTTP 통신 코드는 자바스크립트에서는 비동기적으로 코드를 처리하게 된다.

즉, 위와 같은 코드는 콜백 함수, 프로미스 등을 사용하여야만 실행 순서를 보장 받을 수 있다.

만약, 실행순서를 보장받지 못한다면 ??

console.log(user.name)fetchUser() 보다 호출 스택으로부터 먼저 호출이 되어 undefined 를 출력하게 될지도 모릅니다.

function logFetchUser(findId) {
    var user = fetchUser(`/api/users/${findId}`, (user) => {
    if(isUser(user.id, findId))
        console.log(user.name);
    }); 
}

function isUser(userId, findId) {
    if(userId === findId)
        return true;
    return false;
}

위와 같이 콜백으로 비동기 처리 코드를 작성할 수도 있다. BUT, 콜백은 콜백지옥을 야기할 수 도 있을 뿐만 아니라 위에서 봤었던 개발자가 읽기 좋은 코드 와는 사뭇 다름을 확인할 수 있다.

이를 asyncawait를 사용하여 해결할 수 있다.

async function logFetchUser(findId) {
    var user = await fetchUser(`/api/users/${findId}`);
    if(isUser(user.id, findId))
        console.log(user.name);
}

function isUser(userId, findId) {
    if(userId === findId)
        return true;
    return false;
}

앞에서 설명했듯이, 비동기적 코드가 사용될 함수의 function 앞에는 async를 붙이면 되고 비동기적 코드 fetchUser() 앞에는 await를 붙이면 된다.

결론적으론, asyncawait를 사용함으로서 개발자가 읽기 좋은 코드 와 실행 순서의 보장 을 이뤄낼 수 있다.

asyncawait에 대해 기본 문법을 좀 더 자세히 봐보자.

🌈 async

function 앞에 async를 붙이면 해당 함수는 항상 promise를 반환한다. promise 가 아닌 값을 반환하더라도 이행 상태의 promise로 값을 감싸 이행된 promise가 반환되도록 한다.

async function foo() {
    return 1;
}

foo().then((item) => {
    console.log(item); // 1
});

위의 코드를 실행해 보면 1이 출력되는 것을 확인할 수 있다.

즉, async가 붙은 함수는 반드시 promise를 반환하고, promise가 아닌 것은 promise로 감싸 반환한다.

🌈 await

awaitasync가 붙은 function에서만 사용 가능하다. 자바스크립트는 await 키워드를 만나면 promise즉, 비동기 처리 코드가 수행 완료될 때 까지 기다린다.

결과는 그 다음에 반환된다.

async function bar() {
    let promise = new Promise((resolve, reject) => {
        setTimeout(() => resolve("setTimeOut Finished!"), 1000);
    });

    let result = await promise;

    console.log(result); // setTimeOut Finished!
}

함수를 호출하고, 함수 본문이 실행되는 도중에 await 처리된 줄에서 잠시 1초간 중단되었다가 promise 가 종료되면 실행이 재개되어 콘솔에 출력이 된다.

await를 하는 동안, 엔진이 다른 일을 처리할 수 있기 때문에, CPU 리소스를 낭비하지 않을 수 있다.

await 는 최상위 레벨 코드에서 작동하지 않는다.

let user = await fetchUser(/api/users/1); // Error Occured!
이와 같은 오류는 익명 async 함수로 감싸면 해결할 수 있다.

(async () => {
  let user = await fetchUser(`/api/users/1`);  // Error Occured!
}) ();

awaitthenable 객체를 받는다.

await 에도 then 메서드가 있는 호출 가능한 객체를 사용할 수 있다.

class ThenableClass {
    constructor() {}

    then(resolve, reject) {
        resolve("Hello");
    }
}

async function thenableFunction() {
    let res = await new ThenableClass();
}

클래스 메서드에도 async를 사용할 수 있다.

class AsyncMethod {
    async test() {
        return await new Promise((resolve, reject) => {
            resolve("test");
        });
    }
}

🌈 async & await 예외 처리

promise 가 거부되면 throw문과 같이 에러가 던져진다.

실제 상황에선 promise가 거부 되기 전에 약간의 시간이 지체되는 경우도 있다. 이 땐, await 가 에러를 던지기 전에 지연이 발생한다.

await가 던진 에러는 try catch 를 사용해 잡을 수 있다.

async function awaitErrorEx() {
    try {
        let user = await fetchUser(`/api/users/1`);
    } catch(err) {
        console.error(`Error Occured! : ${err.message}`);
    }
}

또한, .catch를 통해서도 가능하다.

async function awaitErrorEx() {
    let user = await fetchUser(`/api/users/1`);
}

awaitErrorEx()
    .catch((err) => {
        console.error(`Error Occured! : ${err.message}`);
    }
);

asyncawaitPromise.all 과도 함께 쓸 수 있다.

여러 개의 promise가 모두 처리되길 기다려야 하는 상황이라면 Promise.all 로 감싸 await를 붙여 사용할 수 있다.

async function test() {
    let results = await Promise.all([
        fetchUser(url1),
        fetchUser(url2),
        fetchUser(url3)
        ...
    ]);
};

🚀 마무리

지금 까지 asyncawait 에 대해서 살펴보았다.

살펴봤던 내용을 요약하여 보자.

  1. 비동기적 코드의 실행 순서의 보장을 이뤄낼 수 있다.

  2. 개발자가 읽기 좋은 코드를 유지하며 개발이 가능하다.

  3. async 함수는 언제나 promise를 반환한다.

  4. await 키워드를 붙이면 자바스크립트는 promise 가 처리될 때까지 대기한다.

profile
WEB STUDY & etc.. HELLO!

0개의 댓글