async/await 구문 작성 후 무야호를 외치는 방법
Tags: javascript, korean
Published: 2021-03-15 05:54:30

팁 쓰려고 하는데 제목 때문에 시간 잡아먹기 싫어서 어그로 좀 끌었다.

요즘 한국에서도 `async` 구문과 `await` 구문을 쓰면서 자바스크립트 비동기 구문에 무야호~를 외치는 사람들이 늘어나기 시작했다.
콜백 지옥에서 벗어나서 접근하기 어려운 `Promise` 객체를 `async/await` 구문으로 해결하는 기쁨은 말로 표현할 수 없을 것이다. 비동기를 동기처럼 작성할 수 있다는 게 얼마나 기쁜 일인가.

이제 이 구문의 근간이 되는 [코루틴(Coroutine)](https://en.wikipedia.org/wiki/Coroutine)에 대한 개념을 익히면 더 좋겠지만 이건 잠깐 뒤로 미루고, `async/await` 구문을 잘 작성해서 진정한 무야호~를 외치는 방법을 오늘 다루고자 한다.

## `await variable/const/expression`

대부분은 `Promise` 객체를 내뱉는 함수를 `await` 뒤에 넣을 것이다.

```js
async function doSome() {
  const result = await muyaho('api');
  // 무야호~
}
```

그 어느 스터디, 튜토리얼, 팁을 가도 다 이런 식으로 예제를 뿌리고 가르칠 것이다.
하지만 `Promise` 객체라면 꼭 함수가 아니라도 `await` 구문을 넣을 수 있다는 점을 잊지 말자.

```js
async function doSome() {
  const waiting = muyaho('api');
  // 딴짓하기
  const result = await waiting;
  // 무야호~
}
```

이는 흔한 케이스는 아니지만, 부가적으로 가져올 게 있다거나, 벤치마크를 실시하여 순수 비동기 소요 시간을 계산한다던가 등에 쓰임새는 있다.
물론 `Promise` 객체가 아닌 식 및 변수라도 `await` 구문은 다 받아들이며, 당연하겠지만 `Promise` 객체가 아니면 모두 `Promise.resolve()` 정적 메소드의 재물이 될 것이다. 즉, 즉시 완료된 결과가 도출된다는 얘기. 이것도 당연히 알고 있을 테고.
이를 이용해 비동기 처리를 순차적으로가 아닌 동시에 하는 것도 가능하다.

```js
async function doSomeMore() {
  const waiting1 = muyaho('api1');
  const waiting2 = muyaho('api2');
  // 딴짓하기
  const result1 = await waiting1;
  const result2 = await waiting2;
  // 무야호~
}
```

이렇게 하면 비동기 함수 `muyaho` 가 `Promise` 객체 생성하자마자 역할을 끝내 `waiting1` 변수의 비동기 결과를 가져오기 전에 `waiting2` 변수를 가져올 것이다. 물론 `Promise` 객체로.

이렇게 하면 `Promise.all` 같이 동시에 복수 비동기 처리를 어렵지 않게 처리할 수 있다.

**그런데!**

이런 패턴을 쓰기 전에 반드시 짚고 넘어가야 하고, 이번 글의 메일 디쉬이기도 하다. 이 메인 디쉬를 잘 소화한 개발자들은 이제 유연하고 강력한 코루틴의 세계에 흠뻑 빠지며 무야호를 외치면 된다.

## 있었는데 없어진 코루틴 오류

비동기 함수를 사용하면서 예외 처리도 확 편해졌다. 동기식 때처럼 `try/catch` 문을 사용하면 되기 때문이다.

흔치 않은 케이스지만, 비동기 함수를 호출했고 `await` 구문을 아직 쓰지 않았는데 오류가 났다면 당신은 어떻게 대응할 것인가?

자, 여기 테스트 코드를 주도록 하겠다.

```js
// 비동기 딜레이 시뮬레이션용
function delay(fn, time) {
  return new Promise((A,B) => setTimeout(() => {try {A(fn())} catch(e) {B(e)}}, time))
}
// 본격 비동기
(async () => {
  console.log('async prepare!')
  const a = delay(() => console.log('success!'), 1000);
  const b = delay(() => {throw new Error('failed!')}, 500);
  console.log('async ready!')
  try {
    const c = await a;
    const d = await b;
    console.log('async finish!')
  } catch(e) {
    console.log('async failed!')
    console.error(e)
  }
})();
```

여기서 두 개의 비동기 객체를 가져왔는데, 하나는 성공, 하나는 실패를 가져온다.
위 코드를 실행할 경우 개발자 도구의 콘솔 창에서는 이런 식으로 흐른다.

![개발자 도구 콘솔 화면](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fej40qbw5eweqcqs7a5b.gif)

만약 파란 글자로 된 오류 메시지가 안보인다면, 콘솔에서 Level 선택란에 Verbose 항목에 체크하거나, All levels 를 체크하면 된다.
메시지 흐름을 보면 이미 0.5초 뒤 오류를 뿜었는데, 비동기 오류를 뿜는 비동기 함수 수행 후에도 그 다음 구문이 동작한 것을 확인할 수 있다.
그러다가 `await`로 결과를 가져오려 하면, 해당 비동기 루틴은 이미 오류가 났기 때문에 더 이상의 구문은 수행되지 않고 오류를 뿜어내 `catch` 문에 잡힌 것을 볼 수 있다.

여기서 재밌는 사실이 있다면, 실행한 뒤 0.5초 시점에 이미 오류가 났다가, 1초에 재대로 오류가 났다는 것이다. 그러면서 실패 메시지가 출력되었고, 이미 출력된 오류 메시지는 갑자기 사라지면서 `verbose` 레벨, 즉, `debug` 로그 레벨로 갑자기 격하되었다는 사실이다. ~~왜 이렇게 했는지 까지는 안 알아봤으니 누가 알려주면 감사.~~ 그냥 크로미움 등의 브라우저 엔진에서 비동기 오류 발생이 이미 했다 해도 나중에라도 `catch` 이벤트나 `async catch` 구문 걸면 `caught` 처리 되어 기존 `uncaught error` 로그가 `debug` 레벨로 격하된다고 한다. 개발자에게 혼란을 덜 주기 위한 친절한 배려가 아닐 수 없다.[(출처댓글)](https://www.facebook.com/groups/webfrontend/permalink/2283001938511195/?comment_id=2283154768495912&__cft__[0]=AZUzQEZDMOLvmgi7ivB8sRzE3cRrCWF6y4ew6rc1SWGVKDNyUMRGkj3Q4SJJGPaoBC19t5OSaNwtRsMDvTbff9Fnx6TEjTVZvIdQ8RrUa-9-w9aNuu-mI8Ly-5U9wfkOmXU7yfxVpqZVOirhNRo9aBNa&__tn__=R]-R) 

내가 왜 이렇게 코드를 만들었냐면, `await` 전에 비동기 루틴은 오류가 나던 안나던 계속 비동기 함수는 지 할 일 한다는 뜻을 전달하기 위함이다. 그러다 `await` 로 비동기 결과를 가져오려는 순간, 이미 오류가 났기에 메인 비동기 함수는 오류가 났다는 것.
이렇듯 시점이 햇갈리는 비동기 오류가 발생할 수 있으므로,
이를 잘 컨트롤 하는 것이 자바스크립트 코루틴을 잘 다루느냐 못 다루느냐가 결정되는 중요한 요소라는 것이다.

간단히 말하자면, 비동기 오류는 언제든 일어날 수 있으며, 일찍이 잡던 늦게 잡던 잡을 수 있고, 이를 대응할 수 있다는 가정을 가지고 그냥 내가 의도적으로 짠 코드라고 보면 된다. 우연은 없다. 비동기에 익숙하다면 그 뜻을 알리라.

물론 `await muyaho()` 같이 바로 비동기 함수를 실행하고 결과를 가져오는 케이스가 대부분이긴 하지만, 동시성 제어를 고려한다면, 여기서 예기치 못한 오류가 났을 때, 잘 대응하는 방법을 고민해 볼 기회를 주기 위해서다.

이 오류 시점과 오류를 `catch` 하는 시점에 대한 대응이 가능하다면, 당신은 이제 코루틴을 쓰면서 비동기에게 무야호를 시전하면 된다.

끗.