IT Study/JavaScript

[JS] 비동기 처리 패턴 async, await

짹짹체유 2023. 9. 6. 17:42

https://ul0511.tistory.com/25

 

[JavaScript] 핵심 개념(1) 동기·비동기 | 이벤트 루프 | Promise

동기, 비동기 요청 작업을 순서를 지켜서 순차적으로 처리를 하는지 여부에 따라 동기와 비동기로 나눌 수 있다. 동기 처리 방식은 직렬적으로 작업을 수행하고 비동식 처리 방식은 병렬적으로

ul0511.tistory.com

위 글에서 언급은 했지만, 자바스크립트는 싱글 스레드로 비동기 작업을 처리해 주는 작업이 필요하다

비동기 작업을 처리해 주는 객체이자 패턴 중 하나는 Promise이며 이와 유사하게 async와 await도 있다

 

 

async, await

마찬가지로 비동기 처리 패턴 중 하나로 동기 처리처럼 동작하도록 구현할 수 있다.

ES8에서 나온 문법으로서 비동기 코드를 더 읽기 쉽게 작성하도록 도와주는 역할을 한다.

 

async 키워드를 사용한 함수는 Promise를 반환하기에 then, catch, finally 메서드도 연달아 쓸 수 있는 메서드 체이닝이 가능하다.

await 키워드는 프로미스가 settled 상태가 될 때까지 대기를 하다가 settled 상태가 되면 프로미스가 resolve한 결과를 처리한다. 반드시 async 함수 내부에서 사용해야 하며 반드시 프로미스 앞에서 사용해야 한다. await 뒤에 프로미스가 아닌 다른 값이 와도 되지만 코드에 아무런 영향도 미치지 않아서 await를 쓴 효과가 없다.

 

try-catch 구문으로 async/await 형태의 비동기 코드 에러 처리도 가능하다

 

async function runAsyncAwait() {
  try {
    let user = await getUser(1);
  	console.log(user);
  	let post = await getPost(user.id);
  	console.log(post);
  	let comments = await getComments(post[0].id);
  	console.log(comments);
  	return {user, post, comments};
  } catch(err) {
    console.log(err)
  }
}

 

Promise를 async함수로 변경하기

1. 함수에 async 키워드 작성

2. new Promise 부분을 없애고 함수의 본문 내용만 남겨둠

3. resolve(value)를 return value로 바꿔줌

4. reject는 throw로 수정 -> 에러 처리

 

 

then, catch문을 await로 변경하기

1. then, catch문에서 하는 작업을 async func으로 감싸줌

2. async func의 error 처리를 try-catch 문으로 작성

3. async func에 await문 작성

4. 감싼 async func 호출

 

 

비동기 패턴의 발전 과정

1) 콜백함수 ->  2) Promise ->  3) async/await

 

그렇다면, Promise가 async/await를 완전히 대체할 수 있을까?

 

setTimeout에서 resolve는 콜백함수로서 넘어가 task queue로 넘겨주지만, async에서는 return 값으로 넘어가고 콜백함수가 없다. 즉, setTimeout가 끝났을 때 호출하는 콜백함수가 없어서 async로 컨트롤할 수 없기 때문에 Promise가 필요하다.

=> 완전히 대체 불가능

 

 

동시 실행

1. Promise + async

동시 실행을 위해서는 Promise와 async를 같이 써줄 수 있다.

function delay(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

async function getApple() {
    await delay(2000);
    return "apple";
}

async function getBanana() {
    await delay(1000);
    return "banana";
}

// async만 사용
async function fruit() {
    const apple = await getApple();
    const banana = await getBanana();
    console.log(`${apple} + ${banana}`);
}

fruit();
// 3초 걸림


// promise + async를 같이
async function fruit() {
    const [a, b] =  await Promise.all([getApple(), getBanana()]);
    console.log(`${a} + ${b}`);
}

fruit();
// 2초 걸림

 

2. only async

async만으로 동시 실행을 진행시켜줄 수 있다.

function delay(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

async function getApple() {
    await delay(2000);
    return "apple";
}

async function getBanana() {
    await delay(1000);
    return "banana";
}

async function fruit() {
    const promiseapple = getApple(); // pending 상태인 프로미스 자체가 찍히는 것
    // JS엔진 입장에서는 0초 이후 바로 아래 코드 실행
    const promisebanana = getBanana();

    const apple = await promiseapple;
    const banana = await promisebanana;

    console.log(`${apple} + ${banana}`);
}

fruit();

 

반응형