프론트엔드/JavaScript

(JavaScript) 5. 비동기 처리 (Async & Promise)

그린티_ 2025. 5. 1. 21:27
반응형

동기(Synchronous) vs 비동기(Asynchronous)

동기와 비동기는 작업이 실행되는 방식의 차이

- 쉽게 말하면 "순서대로 실행되는가, 동시에 실행되는가"의 차이!

 

 

동기(Synchronous)

- 한 작업이 끝나야 다음 작업이 실행됨

- 순차적으로 실행되기 때문에 코드의 실행 흐름을 예상하기 쉬움

- 하지만 작업 시간이 오래 걸리면 전체 프로그램이 멈춤(= 블로킹 발생)

 

예제: 동기 코드

console.log("A 작업 시작");
console.log("B 작업 실행");
console.log("C 작업 실행");
console.log("D 작업 완료");

실행 순서:

A 작업 시작
B 작업 실행
C 작업 실행
D 작업 완료

- 위에서 아래로 차례대로 실행됨


동기의 문제점

만약 네트워크 요청이나 파일 읽기 같은 시간이 오래 걸리는 작업이 있다면?

console.log("A 작업 시작");

// 5초 동안 멈추는 코드 (가정)
for (let i = 0; i < 5e9; i++) {}

console.log("B 작업 실행");

실행 순서:

A 작업 시작
(5초 동안 멈춤)
B 작업 실행

- A가 끝나야 B가 실행되므로 전체 프로그램이 느려짐


비동기(Asynchronous)

- 작업이 끝날 때까지 기다리지 않고 다음 코드가 실행됨

- 시간이 오래 걸리는 작업(네트워크 요청, 파일 읽기 등)이 있어도 다른 작업이 먼저 실행됨

- 프로그램이 멈추지 않고 계속 실행 가능 → 효율적! 🚀

 

예제: 비동기 코드 (setTimeout 사용)

console.log("A 작업 시작");

setTimeout(() => {
    console.log("B 작업 실행 (3초 후)");
}, 3000);

console.log("C 작업 실행");
console.log("D 작업 완료");

 

실행 순서:

A 작업 시작
C 작업 실행
D 작업 완료
(3초 후) B 작업 실행

✅ setTimeout()은 3초 동안 기다린 후 실행되므로, B가 실행되기 전에 C와 D가 먼저 실행됨


동기 vs 비동기 차이 정리

  동기(Synchronous)  비동기(Asynchronous)
실행 방식 순차적으로 실행 (이전 작업 완료 후 다음 작업 실행) 여러 작업을 동시에 실행 가능
속도 하나씩 실행되므로 느릴 수 있음 오래 걸리는 작업을 기다리지 않아서 빠름
예제 console.log("A"); console.log("B"); setTimeout(() => console.log("B"), 1000);
문제점 하나의 작업이 오래 걸리면 전체가 멈춤 코드가 복잡해질 수 있음 (콜백 문제)

비동기 처리 방법 (콜백, Promise, async/await)

(1) 콜백 함수(Callback)

  • 작업이 끝나면 특정 함수를 실행하도록 함
  • 하지만 콜백이 많아지면 코드가 복잡해지는 문제(콜백 지옥)가 있음
function asyncTask(callback) {
    setTimeout(() => {
        console.log("비동기 작업 완료");
        callback();
    }, 2000);
}

console.log("A 작업");
asyncTask(() => console.log("B 작업"));
console.log("C 작업");

실행 결과:

A 작업
C 작업
(2초 후) 비동기 작업 완료
B 작업

(2) Promise (콜백 지옥 해결)

  • resolve()와 reject()를 이용해 비동기 작업의 성공/실패를 관리할 수 있음
  • then()을 사용해서 체이닝(연결) 가능
function asyncTask() {
    return new Promise((resolve) => {
        setTimeout(() => {
            console.log("비동기 작업 완료");
            resolve();
        }, 2000);
    });
}

console.log("A 작업");
asyncTask().then(() => console.log("B 작업"));
console.log("C 작업");

실행 결과:

A 작업
C 작업
(2초 후) 비동기 작업 완료
B 작업

- 콜백 대신 then()을 사용해서 코드가 깔끔해짐


(3) async/await (가장 추천!)

  • async와 await을 사용하면 동기 코드처럼 읽기 쉽게 비동기 코드 작성 가능
function asyncTask() {
    return new Promise((resolve) => {
        setTimeout(() => {
            console.log("비동기 작업 완료");
            resolve();
        }, 2000);
    });
}

async function run() {
    console.log("A 작업");
    await asyncTask(); // 비동기 작업이 끝날 때까지 기다림
    console.log("B 작업");
    console.log("C 작업");
}

run();

실행 결과:

A 작업
(2초 후) 비동기 작업 완료
B 작업
C 작업

await 덕분에 비동기 작업이 끝날 때까지 기다리고, 이후 작업을 실행함


정리 (언제 사용해야 할까?)

작업 유형 동기(Synchronous) 비동기(Asynchronous)

간단한 연산 (계산, 변수 할당) ✅ 사용 가능 ❌ 필요 없음
네트워크 요청 (API 호출, 데이터베이스 요청) ❌ 느림 (전체가 멈춤) ✅ fetch(), axios() 등 활용
파일 읽기/쓰기 ❌ 느림 ✅ fs.readFile()(Node.js)
애니메이션, UI 변경 ❌ 렉 발생 가능 ✅ setTimeout(), requestAnimationFrame()

결론

  • 동기(Synchronous): 한 번에 한 작업씩 순차적으로 실행됨 → 느릴 수 있음
  • 비동기(Asynchronous): 오래 걸리는 작업을 기다리지 않고 실행 → 빠름
  • 비동기 처리 방법
    • 콜백(Callback) → 코드가 복잡해질 수 있음(콜백 지옥 문제)
    • Promise → .then() 체이닝 가능, 콜백보다 깔끔
    • async/await → 동기 코드처럼 읽기 쉽고 가장 추천!
반응형