본문 바로가기

Programming/JavaScript & TypeScript

await의 함정, 숨은 병목을 찾자

자바스크립트에서 async await을 사용하면 좀 더 깔끔한 코드를 작성할 수 있습니다. 하지만, 적절하게 사용하지 않으면 적지 않은 시간을 사용해야할 수도 있습니다. 특히, 여러개의 await을 사용할 경우에 주의해야합니다.

위와 같은 코드가 있을 때, end를 보려면 얼마나 기다려야할까요?

2,700ms를 기다려야합니다. 생각보다 긴 시간입니다.

Promise.all를 사용해서 시간을 단축해보았습니다. 이제는, 1,900ms만 기다리면됩니다. 800ms나 줄였습니다.

하지만 아직 개선의 여지가 있어보입니다. 

자, 이제 1200ms면 모든 작업을 끝내고, end를 볼 수 있습니다. API의 응답시간 개선 없이 1700ms를 단축했습니다.

 

어째서 이렇게 차이가 나는것 일까요?

async, await을 사용하는 목적은 코드를 동기식으로 작성하기 위함입니다.

1개만 있을 때에는 크게 문제가 되지 않지만, 두 개 이상의 await을 사용할 시에는 의존관계를 면밀히 살펴봐야 할 필요가 있습니다.

 

예를 들어, read와 readSomething은 '독립적인 관계'를 가진 함수입니다. read를 먼저 호출하나, readSomething을 먼저 호출하나 서로에게 영향을 주지 않습니다.

 

반대로, readThat과 checkValidKey는 '의존적인 관계'을 가진 함수입니다. 반드시, readThat이 선행되어야, checkValidKey를 호출할 수 있습니다.

 

또, read와 readSomething은 readThat, checkValidKey 2개의 함수와 '독립적인 관계'를 가진 함수입니다. 세가지 작업을 동시에 비동기적으로 진행하여도 무방합니다.

 

'의존적인 관계'에서는 await을 사용하여 동기식으로 작성하여도 무방합니다. 동기적으로 동작하여야하는 코드이니깐요.

 

그러나, '독립적인 관계'에서는 위의 예시처럼 Promise.all을 사용하거나, 아래와 같이 사용할 수도 있습니다.

1900ms 소모

위의 예시에서, run1, run2, run3은 동시에 시작합니다.

run2 및 run3은 run1 보다 빨리 끝났지만, run1이 아직 끝나지 않아, run1이 끝날 때 까지 기다리게 됩니다.

1200ms 소모

'후속 작업'이 존재하면, 그것을 우선적으로 await 하여, 가능한 빨리 후속 작업을 호출할 수 있도록 하면 됩니다.

 

일반적인 경우에, await을 사용하는 것이 더 깔끔한 코드를 작성할 수 있도록 해줍니다. 또한 대부분의 경우에 API 호출에 오래 걸리지 않습니다. 그렇기 때문에, 적극적으로 await을 사용하는 것을 추천드립니다.

 

하지만, API가 느리거나, 최적화를 원하는 경우(라고 쓰지만, 100ms라도 로딩시간을 줄일 수 있으면 줄이는 것은 매우 좋습니다)에는, 대부분의 경우에 Promise.all같은 기법을 사용해야합니다.

 

두 줄 요약

1. await은 동기식으로 코드를 만들어줌으로, 주의가 필요하다.

2. Promise.all이나, 적절한 await 배치로, 많은 시간을 절약할 수 있다.

 

 

[ 수정내용 ]

- 2020.04.30 가독성을 증대하였습니다.