Promise.then()을 Async/Await 구문과 혼합하면 안 되는 이유

이 문서는 원래 https://maximorlov.com/why-you-shouldnt-mix-promise-then-with-async-await/에 게시되었습니다.

비동기 JavaScript로 작업할 때 엉킨 코드 혼란에 빠진 적이 있습니까? 여기에는 중첩된 콜백이 있고 거기에는 약속이 있으며 이를 마무리하기 위해 반짝거리는 async/await가 있습니다. 😱 🏃🏼‍♂️💨

나는 당신에 대해 모르지만 콜백, 약속 및 async/await가 동일한 함수에 혼합되어 있는 것을 보면 그 밑에 있을 수 있는 버그에 겁이 납니다. 🐛

순수한 async/await로 작성된 비동기 코드를 사용하여 작업하고 가장 중요하게 읽는 것은 신선한 공기의 숨결입니다!

코드가 무엇을 하는지 즉시 이해하고 필요한 경우 쉽게 변경할 수 있습니다.

아아아아. 인생은 좋다. 😌

약속 거부 !== 비동기 오류



하지만 Node.js 프로젝트에서 작업하고 프로덕션 로그에서 처리되지 않은 Promise 거부를 보기 시작했을 때 삶은 그렇게 좋지 않았습니다.

일부 디버깅 후 결국 다음 코드를 사용하여 Express 미들웨어 기능에 대한 문제를 추적했습니다. 무엇이 잘못되었는지 알 수 있습니까?

try {
  const rates = await getCurrencyConversions();
  Price.update({ value: rates.EUR }, { where: { description: "dollar" } })
    .then((result) => {
      return res.status(200).json({ message: "Successfully updated conversion rate.", result });
    });
} catch (error) {
  const message = "Failed to update conversion rate.";
  log.error(message, { error });
  return res.status(500).json({ message });
}


이 코드는 본질적으로 잘못된 것이 아닙니다. 모든 것이 오류 없이 작동하면 예상대로 작동합니다.

일이 예상대로 진행되지 않을 때 우리는 이상한 행동을 알아차립니다. Price.update() 함수에서 오류가 발생하면 어떻게 됩니까?

A: catch 블록에서 오류가 포착되어 기록되고 500 상태 코드가 클라이언트로 전송됩니다.
B: Node.js 프로세스에서 전역unhandledRejection 이벤트가 발생합니다.

.
.
.
.
.

당신은 아마도 내가 이것으로 어디로 가고 있는지 짐작할 수 있을 것입니다. 정답은 B입니다.

대부분의 사람들은 try-블록에서 오류가 발생하면 catch-블록에서 오류를 잡아서 처리할 것이라고 예상할 것입니다. 그러나 이 경우에는 약속이 async/await와 다른 오류 처리 메커니즘을 가지고 있기 때문에 이는 사실과 거리가 멉니다.
Price.update()가 거부하면 가장 가까운 .catch() 메서드를 찾습니다. 아무것도 찾지 못하면 Node.js는 전역unhandledRejection 이벤트를 내보냅니다.

설상가상으로 Node.js 15 or higher and your application doesn't have an unhandledRejection event listener 을 사용하면 서버가 다운됩니다!
.catch() 메서드를 Price.update()에 추가하여 문제를 해결할 수 있었지만 결국 예외 처리를 담당하는 두 곳(.catch() 메서드 및 catch-block)이 생깁니다. 오류를 한 곳에서 처리하면 코드를 유지 관리하기가 더 쉽습니다.

나는 일반적으로 async/await 구문을 고수할 것을 권장합니다. 함수가 약속을 반환하는 경우 async/await를 사용할 수도 있으므로 두 구문을 혼합할 필요가 없습니다. Async/await는 결국 Promise 위에 구축됩니다.

Note: An exception to this rule is when you're running multiple complex asynchronous flows using Promise.all, at which point you likely have a solid understanding of how promises work and you're able to work your way around unexpected behaviour that arises from mixing async/await with Promise.then() syntax.



버그의 원인을 파악한 후 코드를 async/await로 리팩터링하고 .then() 메서드를 제거했습니다.

try {
  const rates = await getCurrencyConversions();
  const result = await Price.update(
    { value: rates.EUR },
    { where: { description: "dollar" } }
  );
  return res.status(200).json({ message: "Successfully updated conversion rate.", result });
} catch (error) {
  const message = "Failed to update conversion rate.";
  log.error(message, { error });
  return res.status(500).json({ message });
}


그 후, 처리되지 않은 약속 거부가 로그에서 사라지고 삶이 다시 좋아졌습니다! 💫

마스터 비동기 자바스크립트 🚀



무료 5일 이메일 과정을 통해 현대적이고 읽기 쉬운 비동기 코드를 작성하는 방법을 배우십시오.

시각적 그래픽을 통해 비동기 코드를 개별 부분으로 분해하고 최신 async/await 접근 방식을 사용하여 다시 결합하는 방법을 배웁니다. 또한 30개 이상의 실제 연습을 통해 지식을 더 나은 개발자가 될 실용적인 기술로 전환할 수 있습니다.



👉 Get Lesson 1 now

좋은 웹페이지 즐겨찾기