JavaScript & Node.js

#.14 비동기 [async, await]

Haksae 2022. 1. 9. 15:44

*Async & Await

  • promise를 통해서 비동기적으로 처리하게되면 코드가 복잡해질 수 있는데,
  • Async와 Await를 활용하면 promise를 간결하고 간편하고 동기적으로 실행하는 것처럼 보이게 한다 (syntactic sugar)
    • 그렇다고 promise가 나쁘고 꼭 대체해야 되는 것은 아니다.
    • promise를 유지해야 맞는 경우가 있고 async& await으로 바꿔줘야 하는 경우가 있다.

1. Async

  • 동기 처리의 한계
function fetchUser(){
    // do network request in 10 secs...
    return 'haksae';
}

const user = fetchUser();
console.log(user);
  • 이런 코드는 10초 정도 유저가 텅 빈 브라우저를 보기 때문에 비동기적으로 처리해야 한다.
  • promise
    • executor(resolve, reject) 콜백함수를 호출하지 않으면 아래와 pending 상태가 된다.
function fetchUser(){
    return new Promise((resolve, reject)=>{
        // do network request in 10 secs...
        return 'haksae';
    });
}

const user = fetchUser();
console.log(user);
  • resolve, reject 호출
function fetchUser(){
    return new Promise((resolve, reject)=>{
        // do network request in 10 secs...
        resolve('haksae');
    });
}

const user = fetchUser();
user.then(console.log);
async function fetchUser(){
    // do network request in 10 secs...
    return 'haksae';
}

const user = fetchUser();
user.then(console.log);
console.log(user);
  • async로 간단하게 변환
async function fetchUser() {
  return "haksae";
}

const user = fetchUser();
user.then(console.log);
console.log(user);

2. await

  • async가 붙은 함수 안에서만 사용가능
  • chaining보다는 동기적인 것처럼 보이는 async사용 → 코드 쉽게 이해할 수 있음
function delay(ms){
    return new Promise(resolve => setTimeout(resolve, ms));
}

async function getApple(){
    await delay(3000);
    return '🍎';
}

// chaining보다는 동기적인 것처럼 보이는 async사용
// 코드 쉽게 이해할 수 있음
// function getBanana(){
//     return delay(3000)
//         .then(()=>'🍌');
// }

async function getBanana(){
    await delay(3000);
    return '🍌';
}
// chaining > promise도 너무 중첩적으로 하면 콜백지옥과 비슷한 문제점 발생
function pickFruits(){
    return getApple()
            .then(apple => {
                return getBanana()
                    .then(banana => `${apple} + ${banana}`);
            })
}

pickFruits().then(console.log);
//* async 사용하여 해결
// 코드를 작성이 동기적인 방식으로 하는 것처럼 쓰고 리턴값도 있어 간편
async function pickFruits(){
    const apple = await getApple();
    const banana = await getBanana();
    return `${apple} + ${banana}`;
}

pickFruits().then(console.log);

3. await 병렬 처리

  • 동시다발적으로 수행 가능한 코드를 병렬적으로 처리
async function pickFruits(){
    
    //병렬 처리
    const applePromise = getApple();  // 1초
    const bananaPromise = getBanana(); // 1초
 
    // 총 1초
    const apple = await applePromise;
    const banana = await bananaPromise;
    return `${apple} + ${banana}`;
  • 그러나 병렬 처리가 가능한 상황에서는 promise API를 통해서 더 꺠끗하게 코드 작성 가능
  1. promise.all()
  • promise배열을 전달하면 모든 promise들이 병렬적으로 다 받을 때까지 모아준다.
  • all<T1, T2>(values: readonly [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>]): Promise<[T1, T2]>;
function picKAllFruits(){
    return Promise.all([getApple(), getBanana()])
            .then(fruits => fruits.join(' + '));
}

picKAllFruits().then(console.log);
  1. promise.race()
  • 비동기 처리중 가장 먼저 리턴되는 promise 배열을 출력한다
  • race<T>(values: readonly T[]): Promise<T extends PromiseLike<infer U> ? U : T>;
function pickOnlyOne(){
    return Promise.race([getApple(), getBanana()]);
}

pickOnlyOne().then(console.log);

 

출처 : 드림코딩엘리 https://www.youtube.com/channel/UC_4u-bXaba7yrRz_6x6kb_w