WIKI비동기
플레이북

비동기

기다림 많은 일을 멈추지 않고 처리하는 법.

비동기콜백프로미스async/await자바스크립트백엔드 기초
비동기Java 개발자4분

한눈에

  • 비동기 = 기다리는 시간에 다른 일 하기 (라면 끓는 동안 설거지)
  • 동기 = 앞사람 끝나야 내 차례 (냄비만 쳐다보며 대기)
  • 콜백 = 끝나면 이 함수 불러줘 (겹치면 콜백 지옥)
  • 프로미스 = 나중에 값이 담길 상자 (.then() 체인, .catch() 에러)
  • async/await = 비동기를 동기처럼 위에서 아래로 (지금 표준, 속은 프로미스)
  • 프로미스 = Java의 Future (단 await는 스레드를 멈춰 세우지 않는다)

라면을 끓인다고 하자. 물을 올려놓고 냄비만 뚫어지게 쳐다보며 서 있는 사람은 없다. 끓는 동안 설거지를 하고, 빨래를 돌리고, 그러다 물이 끓으면 그때 면을 넣는다. 이게 비동기다. 반대로 냄비 앞에 딱 붙어 다 끓을 때까지 아무것도 안 하고 서 있는 게 동기다. 한 줄로 하면, 비동기는 "기다리는 시간에 다른 일을 하는" 방식이다.

동기와 비동기

동기(synchronous)는 줄을 선다. 앞사람 일이 끝나야 내 차례가 온다. 은행 창구가 한 줄뿐이면, 앞 손님 업무가 30분 걸릴 때 뒤는 그냥 멈춰서 기다린다. 코드로 치면 한 줄이 끝나야 다음 줄이 실행되는 것.

비동기(asynchronous)는 맡겨두고 다음 일을 한다. 번호표를 뽑고 자리에 앉아 다른 일을 보다가, 내 번호가 불리면 그때 창구로 간다. 창구가 여러 손님을 병렬로 굴리는 동안 나도 멈추지 않는다.

왜 굳이 이렇게

핵심은 기다림이 많은 작업이다. 파일 읽기, 네트워크 요청, DB 조회 — 이건 내 프로그램이 열심히 계산하는 게 아니라 결과가 올 때까지 그냥 기다리는 일이다. 이걸 동기로 처리하면 기다리는 내내 프로그램 전체가 멈춘다. 손님 100명이 각자 파일 하나씩 읽어달라고 하는데, 한 명 끝날 때까지 나머지 99명이 대기하는 꼴.

비동기면 다르다. A의 파일 읽기를 걸어두고 — 기다리지 않고 — 바로 B를 처리하고, C를 처리하다가, "A 파일 다 읽었어요" 하면 그때 A에게 돌려준다. 기다림이 많을수록 이 방식이 압도적으로 유리하다.

콜백 → 프로미스 → async/await

비동기는 결국 **"결과가 오면 이걸 해줘"**를 어떻게 적느냐의 문제다. 이 표현법이 세 단계로 진화했다.

콜백이 처음이었다. "끝나면 이 함수를 불러줘" 하고 함수를 넘긴다. 하나면 깔끔한데, 순서대로 여러 개를 엮으면 문제가 생긴다. A 끝나면 B, B 끝나면 C, C 끝나면 D... 함수 안에 함수가 계단처럼 겹겹이 쌓인다. 이게 악명 높은 콜백 지옥이다. 오른쪽으로 밀려나는 코드는 읽기도, 에러 잡기도 지옥이다.

**프로미스(Promise)**가 이걸 폈다. "나중에 값이 담길 상자"를 먼저 돌려주는 것. .then()으로 이어붙이면 계단이 세로 체인으로 펴진다. .catch()로 에러도 한곳에서 잡는다.

async/await가 마지막이자 지금 표준이다. 비동기인데 동기처럼 위에서 아래로 읽힌다. await를 붙이면 "여기서 결과를 기다렸다가 다음 줄로" 라는 뜻인데, 겉보기엔 평범한 순차 코드라 눈에 제일 편하다. 속은 여전히 프로미스다.

콜백
끝나면 이 함수 불러줘 — 겹치면 콜백 지옥
프로미스
나중에 값이 담길 상자, .then()으로 체인
async/await
비동기를 동기처럼 위에서 아래로 읽기

Java 하던 사람 기준 다리

낯선 개념이 아니다. Java에도 다 있던 것이고, 자리만 조금 다르다.

Future ↔ 프로미스 — 나중에 채워질 결과를 담는 상자
CompletableFuture.thenApply() ↔ .then() — 결과가 오면 이어서 처리
future.get() (블로킹) ↔ await — 결과를 기다렸다 받되, await는 스레드를 멈춰 세우지 않는다
new Thread(...)로 동시 처리 ↔ 단일 스레드 저글링 — Java는 스레드를 더 붙여 흉내내고, 자바스크립트는 한 스레드로 기다림을 저글링한다

여기서 한 가지 감각 차이가 크다. Java에서 "비동기"라고 하면 보통 스레드를 하나 더 띄워 옆에서 돌리는 그림을 떠올린다. 자바스크립트의 비동기는 그게 아니라, 한 스레드가 기다림을 저글링하는 방식이다. 그래서 스레드를 새로 파던 습관을 그대로 옮기면 오히려 어색하다 — 여기선 그냥 await를 걸어두면 런타임이 알아서 다른 일로 넘어간다.

우리 프로젝트에선

이 0to1 블로그를 굴리는 Node 스크립트들이 전부 비동기로 짜여 있다. 파일을 읽고, git 로그를 긁고, 글 목록과 신선도 점수를 만드는 일 — 죄다 "기다림이 많은 작업"이라 비동기가 자연스럽게 온다.

사실 비동기는 Node 노트의 이벤트 루프와 한 몸인 개념이다. 이벤트 루프가 "기다리며 멈추지 않고 저글링하는 심장"이고, 비동기는 그 심장이 굴리는 일 처리 방식이다. 콜백·프로미스·async/await는 그 저글링을 코드로 어떻게 적느냐의 문제일 뿐이다. 그래서 둘은 같이 봐야 그림이 맞는다 — 심장 쪽이 궁금하면 Node로.

더 읽기

비유와 예제로 더 풀어놓은 글들. 진화 순서대로 하나씩 따라가면 좋다.