async/await는 왜 비동기일까?

async/await가 비동기 문법이라고?? 왜??
asyncawaitasync/await비동기비동기문법fetchpromise
avatar
2025.03.10
·
7 min read

저는 스프링을 사용하는 개발자입니다 !

JSP까지 같이 사용하고 있기 때문에 View에서 비동기 통신을 주로 사용하곤 하는데요

주로 Fetch를 자주 사용하고 있습니다.

fetch는 Promise 타입 기반이므로 체이닝을 활용할 수 있는 비동기 통신 기법 중 하나로,

2015년 ES6(ECMAScript 2015)에서 등장했습니다.

fetch는 등장 이후 내부적으로 Promise 타입을 사용하여 더 직관적이고 체계적인 비동기 요청 방식을 제공하고 있습니다.

// 간단한 get요청
fetch("https://api.namba.com/data")
  .then(response => response.json()) // 응답을 JSON으로 변환
  .then(data => console.log(data))
  .catch(error => console.error("Error:", error));

// Post, put, delete 요청
fetch("https://api.namba.com/data", {
  method: "POST",  // 요청 방식 (POST, PUT, DELETE 가능)
  headers: {  // "headers"는 객체로 작성해야 함
    "Content-Type": "application/json"
  },
  body: JSON.stringify({  // 요청 본문 (JSON 형태로 변환)
    key1: "value1",
    key2: "value2"
  })
})
  .then(response => {
    if (!response.ok) {
      throw new error();
    }
    return response.json();
  }) // 응답을 JSON으로 변환
  .then(data => console.log("응답 데이터:", data))
  .catch(error => console.error("에러 발생:", error));

fetch를 사용하다보면 가끔 로직에 따라 async/await를 사용하곤 하는데요

function 내부에 비동기 통신 이후 그 값을 기반으로 프로세스를 작성하다보면

await로 값을 대기하다 실행하는 흐름을 볼 수 있습니다.

async function fetchData() {
  console.log("1. 요청 보냄");
  const response = await fetch("https://api.namba.com/data");
  console.log("2. 응답 받음");
  const data = await response.json();
  console.log("3. 데이터 출력:", data);
}

위와 같이 사용을 하다보면 동기 통신과 같은 역할을 하는 것 같기도 한데 여기서 든 의문은

async/await는 동기적인 프로세스를 보여주는데 왜 비동기 문법으로 칭하는 지 의문이 들었습니다.

결과론적으로 동기와 비동기의 가장 큰 "어떤 방식으로 작업을 기다리는가?"에 초점을 잡아보면 이해할 수 있습니다.

구분

동기(Synchronous)

비동기(Asynchronous)

Thread 상태

요청을 보내고 응답을 받을 때까지

대기 (Blocking)

요청을 보내고 다른 작업 수행 가능

(Non-Blocking)

작업 흐름

직렬 처리 (순차적 실행)

병렬 처리 가능 (다른 작업과 병행 실행)

위와 같은 표를 보신다면 Blocking에 대한 차이라는 걸 확인할 수 있습니다.

말이 어려워도 Blocking은 다음 사진과 같습니다.

3817

최상위 Thread가 작업을 멈추고 결과를 기다리는 것 !! 그게 Thread Blocking 입니다.

그렇다면 async/await를 함수 내부에서 사용할 때 await 때문에 다른 로직이 실행이 안될까요?

async function fetchData() {
  console.log("1. 요청 보냄");
  const response = await fetch("https://api.namba.com/data");
  console.log("2. 응답 받음");
  const data = await response.json();
  console.log("3. 데이터 출력:", data);
}

console.log('작업 진행 중 1');
fetchData();
console.log('작업 진행 중 2');

위의 결과를 확인한다면

작업 진행 중 1
1. 요청 보냄
작업 진행 중 2
2. 응답 받음  (fetch 응답 도착 후)
3. 데이터 출력: { ... } (JSON 변환 후)

위와 같은 결과를 확인할 수 있습니다.

분명 await로 값을 대기할 순 있지만 ThreadBlocking은 이루어지지 않죠

await가 실행되면, 해당 Promise가 해결될 때까지 기다리지만, 다른 작업(이벤트 루프, 다른 태스크)은 정상적으로 실행됩니다.

이러한 차이때문에 async/await는 동기 문법이라고 할 수 없는 겁니다 !!!

단, 최상위 Thread에서 async/await를 사용한다면 Thread 자체가 Blocking 되는 상황을 만들 수도 있기 때문에 항상 조심해서 코드를 잘 짜야됩니다 ㅎㅎ

결론적으로, async/await는 동기적 스타일로 코드를 작성할 수 있게 해주는 비동기 문법입니다 !


혼자 재미있는 고민을 해봤는데요 ㅎㅎ

JavaScript는 Single Thread 기반 언어입니다.

Single Thread라고 함은 하나의 작업이 멈춘다면 (blocking) 서버 전체가 먹통이 된다는 말이죠

Multi Thread 환경인 Spring에서는 그렇게 위협적이지 않은 동기 통신도 Single Thread 환경은

그렇지 않다는 얘기가 되겠죠 ㅎㅎ

이를 해결하기 위해 비동기 이벤트 루프(Event Loop)와 콜백 큐(Task Queue) 시스템이 발전했다고 합니다.

그렇기때문에 Single Thread 환경에 맞게끔 비동기 통신이 발전되어 우리들이 비동기 통신을 잘 사용하고 있을 지도 모르겠네요 ㅎㅎ

또한, 단순히 Single Thread라서 발전한 것만은 아니고, 더 효율적인 CPU 활용을 위해 발전해 왔다는 점과 그렇기 때문에 비동기 프로그래밍은 Multi Thread 환경에서도 유용하다는 점도 알아가시면 좋을 것 같습니다 !

오늘은 async/await에 대해 알아보았습니다 !







- 컬렉션 아티클