"네트워크 요청 하나 보냈을 뿐인데, 브라우저가 멈춘 느낌이 들었다면 여기서부터 다시 정리."
자바스크립트로 프론트 개발하다 보면 동기 / 비동기 이야기는 계속 나온다.
- API 호출, 파일 읽기, 애니메이션처럼 대기 시간이 긴 작업 처리할 때
- 화면이 멈추지 않게 UX를 지키고 싶을 때
- async/await, Promise, 콜백 지옥 같은 것들이 왜 필요한지 이해하고 싶을 때
결국 이 모든 이야기의 바닥에는 동기(Sync)와 비동기(Async)가 깔려 있다.
동기/비동기를 감으로만 아는 상태 → 말로 설명할 수 있는 상태까지 끌어올리기 위한 정리다.
결론 먼저
짧게 정리하면 이렇게 볼 수 있다.
- 동기(Synchronous)
- 앞 작업이 끝나야 다음 작업이 시작된다.
- 흐름이 단순해서 이해하기 쉽지만, 대기 시간이 길면 전체가 같이 묶인다.
- 비동기(Asynchronous)
- 기다리는 동안에도 다음 작업을 계속 진행한다.
- 완료된 작업은 나중에 콜백/Promise/async 함수를 통해 처리한다.
그림으로 보면 느낌이 좀 더 와 닿는다.
[동기] (앞이 끝나야 다음)
Task1 ───▶ Task2 ─▶ Task3 ─▶ Task4
총 시간 = 모두 합계
[비동기] (대기 없이 진행, 완료되면 처리)
Task1 ──────┐
Task2 ──┐ ├─ 완료 알림 순서대로 처리 (콜백 / Promise / await)
Task3 ─────┤
Task4 ───┘
총 시간 = 가장 오래 걸리는 작업
이미지로 보면 이런 느낌이다.

이미지 출처
1. 왜 알아야 할까?
동기/비동기를 알아야 하는 상황은 생각보다 많다.
- 네트워크 요청
- fetch, AJAX, 파일 업로드처럼 시간이 오래 걸릴 수 있는 작업
- 애니메이션 / 스크롤 / 사용자 입력
- 이 작업들과 API 호출이 같은 스레드(메인 스레드)에서 돌아간다.
- UX와 성능
- 한 번 잘못 막아버리면 "버벅임이 느껴지는 서비스"가 되기 쉽다.
결국 한 줄로 요약하면
"동기/비동기를 이해 못 하면, 어느 순간부터 성능과 UX가 같이 망가진다."
라서, 프론트 개발한다면 한 번은 짚고 넘어갈 수밖에 없는 주제다.
2. 동기(Synchronous)
먼저 동기부터 보자.
동기의 특징
- 작업이 순서대로 한 줄로 수행된다.
- 앞에 있는 작업이 끝나야 그다음 작업이 시작된다.
- 코드 읽기가 쉽고 디버깅이 단순하다.
- 대신, 느린 작업 하나가 있으면 뒤에 있는 모든 작업이 같이 기다린다.
자바스크립트에서 자주 보는 동기 작업 예시는 이런 것들이다.
- 일반적인 함수 호출
- JSON.parse, Math 연산 같은 순수 계산
- localStorage.getItem() / setItem()
- (과거) 동기 XHR 같은 것들
간단한 예시를 보자.
function task1() {
console.log("1 시작");
}
function task2() {
console.log("2 시작");
}
task1();
task2();
console.log("끝");
// 항상
// 1 시작
// 2 시작
// 끝
// 이 순서로 찍힌다.
코드는 읽기 쉽지만, 만약 task1()이 네트워크 요청 같은 느린 작업이라면
그 순간 화면 전체가 멈춘 것처럼 느껴질 수 있다.
3. 비동기(Asynchronous)
이번에는 비동기
비동기의 특징
- 시간이 오래 걸리는 작업을 "나중에 처리할 일"로 넘겨둔 채
- 지금 할 수 있는 일들을 계속 진행한다.
- 작업이 끝난 시점에 콜백, Promise, async/await 형태로 결과를 받는다.
- 메인 스레드가 한 작업에 묶이지 않기 때문에, UI/애니메이션이 부드럽게 유지된다.
자바스크립트에서 자주 보는 비동기 작업 예시는 이런 것들이다.
- fetch, AJAX 요청
- setTimeout, setInterval
- 이벤트 리스너 (click, scroll, input 등)
- requestAnimationFrame
- Promise, async/await 조합
- WebSocket 메시지 수신
예시 코드를 보자.
console.log("요청 전");
setTimeout(() => {
console.log("3초 뒤 작업 완료");
}, 3000);
console.log("요청 후");
// 실제 출력 순서
// 요청 전
// 요청 후
// 3초 뒤 작업 완료
코드를 위에서 아래로 읽으면 setTimeout이 가운데 있으니까
"요청 전 → 3초 뒤 작업 완료 → 요청 후"를 기대할 수도 있다.
하지만 비동기에서는 대기 시간 동안 메인 흐름을 막지 않는다.
그래서 아래 줄이 먼저 실행되고, 나중에 콜백이 실행된다.
4. 동기 vs 비동기 한 번에 비교
한 번에 정리해 보면 이렇게 볼 수 있다.
| 비교 항목 | 동기식(Sync) | 비동기식(Async) |
| 실행 방식 | 순차 실행 (앞이 끝나야 다음) | 대기 시간 동안에도 다른 작업 진행 |
| 대기 | 느린 작업이 있으면 전체가 같이 대기 | 느린 작업은 따로 처리, 메인 흐름은 계속 진행 |
| 성능 체감 | 느린 작업 하나가 전체를 끌어내리는 느낌 | 느린 작업을 분리해서, 전체는 상대적으로 부드럽게 유지 |
| JS 관점 | 호출 스택에서 바로 실행 | 이벤트 루프 + 큐에서 나중에 콜백/작업이 실행 |
| 대표 예시 | 일반 함수 호출, JSON.parse, localStorage | fetch/AJAX, Promise, async/await, 이벤트, setTimeout |
여기까지 이해하면, 이제 문서에서 나오는
"이건 비동기라서 이벤트 루프가 어쩌고…" 같은 설명이 훨씬 덜 낯설어진다.
5. 마무리 메모
마지막으로, 이 글을 정리하면서 같이 보면 좋은 문서, 참조한 문서들을 남겨둔다.
- https://developer.mozilla.org/ko/docs/Glossary/Synchronous
- https://developer.mozilla.org/ko/docs/Glossary/Asynchronous
- https://medium.com/@vivianyim/synchronous-vs-asynchronous-javascript-de4918e8ad62
- https://adrianmejia.com/asynchronous-vs-synchronous-handling-concurrency-in-javascript/
- https://evan-moon.github.io/2019/09/19/sync-async-blocking-non-blocking/
'FrontEnd > web' 카테고리의 다른 글
| [실무 기록] <link rel="stylesheet">로 CSS 불러오는데 간헐적으로 CORS 에러가 나던 이유 (해결: crossorigin 제거) (1) | 2026.01.13 |
|---|---|
| [실무 기록] Chrome Inspect에서 Pending authentication만 뜨고 안드로이드 디버깅이 안 될 때 (0) | 2026.01.12 |
| [실무 기록] 웹뷰 브릿지, 이거 누가 책임져야 하지? (0) | 2025.12.10 |
| 검색 엔진 크롤링과 자바스크립트 렌더링 정리 (3) | 2025.09.08 |
| 브라우저 동작 원리 - 화면이 그려지기까지 (0) | 2024.12.06 |
