woolta

async / await 최적화 방법 (병렬처리)

wooltaUserImgb00032 | javaScript | 2019-06-09

async, await 은 비동기 처리를 위해 ES2017 부터 생성된 문법입니다. async, await 을 사용하게 되면 promise 보다 더욱 직관적인 코드를 짤 수 있게 됩니다.

Promise 를 이용한 비동기 처리

function getUsers(){
   const users = this.getUsersFromApi()                         
            .then(users => {
                  return users;
            })
}

Promise 를 사용할 경우 callBack을 사용하는 방법보다 훨씬 깔끔하고 직관적인 코딩이 가능합니다. 그러나 async / await을 사용하게 되면 이보다 더욱 간결하게 처리가 가능합니다.

async / await 를 이용한 비동기 처리

async function getUsers(){
   const users = await this.getUsersFromApi();
}

다음과 같이 async / await 을 이용하여 더욱 간결하게 비동기 요청을 처리할 수 있습니다.

async / await 을 활용한 반복문 처리

이번에는 async await 을 활용하여 반복문을 처리해보도록 하겠습니다. 우선 비동기 처리를 위해 다음과 같은 비동기 호출 샘플을 먼저 작성하도록 하겠습니다.

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

async function waitLog(item){
    await wait(500);
    console.log(`waitLog : ${item}`);
}

위의 비동기 샘플함수 waitLogsetTimeout 함수를 이용해 강제로 500ms 동안 지연시킨 후 로그를 찍는 간단한 함수 입니다.

forEach 를 사용한 반복 처리

async function AsyncAwaitByForEach() {
    [1, 2, 3].forEach(async index => await this.waitLog(index));
    console.log('end');
};

다음과 같이 forEach 를 사용하여 1,2,3 의 배열을 반복시켜 비동기 처리를 요청하였습니다. 이 경우 콘솔에 찍히는 값은 1, 2, 3 ,'end' 로 찍힐것으로 기대할 수 있습니다.

forEach 함수 실행 결과

https://image.woolta.com/3fc6675ca6f44004.png

oops. 예상했던 것과 달리 end 가 먼저 실행되고 1,2,3 이 실행되는 모습입니다. forEach반복문 전체가 종료되는 것에 대한 결과를 기다려주지 않습니다. 때문에 end 가 먼저 실행되고 나머지 1,2,3 이 순차적으로 실행된 것 입니다.

FOR…OF 를 사용한 반복 처리

위와 같은 경우 때문에 반복문이 끝난 뒤 작업을 해야하는 상황이면 ForEach 가 아닌 For...of 를 사용해서 처리하면 됩니다.

async function AsyncAwaitByForOf() {
    const arrays = [1, 2, 3];

    for (const index of arrays) {
        await this.waitLog(index);
    }

    console.log('end');
}

FOR…OF 함수 실행 결과

https://image.woolta.com/3fbf7255d17f0068.png

원래 기대했던 1,2,3,'end' 순으로 출력되는 모습을 볼 수 있습니다. :)

비동기 병렬 처리를 통한 최적화

async / await을 사용하여 비동기 작업을 배열 로 처리하는 경우 순서가 보장되어야 하는 상황이 아니라면 병렬로 처리해 최적화를 할 수 있습니다.

기존 배열 반복 실행 시간 측정

위에서 사용한 AsyncAwaitByForOf 함수의 수행 속도를 console.time을 사용해 측정해 보도록 하겠습니다. 우선 다음과 같이 측정을 위한 console을 추가합니다.

async function AsyncAwaitByForOf() {

    console.time("calculatingTime");
    const arrays = [1, 2, 3];

    for (const index of arrays) {
        await this.waitLog(index);
    }

    console.log('end');
    console.timeEnd("calculatingTime");

}

https://image.woolta.com/3feb101df1c4a32b.png

실행시간이 약 1508ms 가 나왔습니다. 한번의 비동기 처리가 500ms 걸리도록 세팅되어 있고 이를 3번 반복한 측정 결과 입니다.

비동기 병렬 처리

mappromise.All 을 사용하게 되면 병렬 처리가 가능해집니다. 우선 map 을 사용하여 Promise를 반환하도록 하고 이를 promise.All로 통해서 한번에 처리하게 하면 순차적인 병렬 처리가 가능합니다.

async function AsyncAwaitByForOfParallel() {
    console.time("calculatingTime");
    const arrays = [1, 2, 3];
    const arrayPromises = arrays.map(this.waitLog);
    await Promise.all(arrayPromises);
    console.log('end');
    console.timeEnd("calculatingTime");

}

https://image.woolta.com/3fdf55c64b46f9d2.png

위와 같이 병렬로 처리할 경우 더욱 빠른 처리가 가능합니다.

참조

javascript-loops-how-to-handle-async-await

async-functions

Copyright © 2018 woolta.com

gommpo111@gmail.com