JS로 알아보는 동기처리와 비동기 처리의 차이점

홍규진·2025년 4월 2일

비동기처리

목록 보기
1/1

프로그래밍을 처음 배울 때 가장 헷갈리는 개념 중 하나가 바로 동기와 비동기다. 이 요청이 커피숍에서 주문을 하고 기다리는 방식을 생각해보자. 주문 후 카운터에서 커피가 나올 때까지 꼼짝 않고 기다리는가, 아니면 진동벨을 받고 자리에 앉아 다른 일을 하는가? 이것이 바로 동기와 비동기의 차이를 가장 쉽게 설명하는 예시다.

(👨🏻‍🏫 : 하나의 주문이 들어오면 하나를 만드는 동안, 아무것도 안 하는 식당이 있나요? 있긴 하죠. 오마카세… 하지만 비용이 정말 많이 들죠? 이게 바로 동기식 식당 운영이랍니다!)

💡급하신 분들을 위해서 결론 먼저!

  1. 동기 처리는 작업을 순차적으로 실행하며, 하나의 작업이 완료될 때까지 다음 작업은 대기한다.
  2. 비동기 처리는 작업의 완료를 기다리지 않고 다음 작업을 실행할 수 있어 효율적이다.
  3. 동기는 설계가 간단하고 직관적이지만 블로킹으로 인한 성능 저하가 발생할 수 있다.
  4. 비동기는 자원을 효율적으로 사용할 수 있지만 코드가 복잡해질 수 있다.
  5. 상황에 맞게 적절한 방식을 선택하는 것이 중요하다.

1. 동기(Synchronous)와 비동기(Asynchronous)의 기본 개념

동기(Synchronous) 처리란?

동기 처리는 말 그대로 '동시에 일어난다'는 의미를 가진다. 요청과 그 결과가 동시에 일어난다는 약속이다. 작업을 요청하면 그 작업이 완료될 때까지 기다린 후에 다음 작업을 수행한다. 이는 마치 은행 창구에서 한 명의 고객이 업무를 마쳐야 다음 고객이 업무를 볼 수 있는 것과 같다. 은행은 효율보다, 하나의 고객의 경험을 위해서 동기식 처리를 택한 것이다.

비동기(Asynchronous) 처리란?

비동기 처리는 '동시에 일어나지 않는다'는 의미를 가진다. 요청과 결과가 동시에 일어나지 않을 거라는 약속이다. 하나의 요청에 대한 응답을 즉시 처리하지 않아도, 그 대기 시간 동안 다른 요청을 처리할 수 있는 방식이다. 카페에서 커피를 주문하고 진동벨을 받아 자리에 앉아 기다리는 것과 유사하다.

(👨🏻‍🏫 : 비동기는 마치 멀티태스킹 같은 거랍니다. 안성재 셰프는 요리할 때 물을 끓이면서 야채를 썰고, 그러면서 또 소스를 만드는 식으로 일을 처리하는데, 이게 바로 비동기식 작업의 좋은 예시죠!)


2. 동기와 비동기의 작동 방식 차이

동기 방식의 작동 원리

동기 방식에서는 작업이 순차적으로 실행된다. 현재 실행 중인 태스크가 있다면 다음 태스크는 현재 태스크가 완료될 때까지 기다려야 한다. 이는 블로킹(Blocking) 방식으로도 불리며, 한 작업이 다른 작업을 차단하는 특성을 가진다.

예를 들어, 계좌 이체와 같은 작업은 동기 방식으로 처리되어야 한다. A의 계좌에서 B의 계좌로 송금할 때, 두 계좌의 잔액 변경이 동시에 이루어져야 하기 때문이다.

// 동기 방식의 파일 읽기 예제
// 파일 읽기 -> content 콘솔에 찍기 -> 파일 읽기 완료 콘솔에 찍기
function readFileSynchronously(filename) {
  const content = fs.readFileSync(filename, 'utf-8');
  console.log(content);
  console.log('파일 읽기 완료');
}

출처: Node.js 공식 문서 https://nodejs.org/api/fs.html

비동기 방식의 작동 원리

비동기 방식에서는 현재 실행 중인 태스크가 완료되지 않아도 다음 태스크를 실행할 수 있다. 이는 논블로킹(Non-blocking) 방식으로, 작업이 완료될 때까지 기다리지 않고 다른 작업을 수행할 수 있다.

시험 시간을 예로 들면, 학생이 시험지를 풀고 선생님에게 제출한 후, 선생님이 채점하는 동안 학생은 다른 과목을 공부하거나 휴식을 취할 수 있다. 이것이 바로 비동기 방식의 예시다.

// 비동기 방식의 파일 읽기 예제
// 파일 읽기 요청 완료 -> 파일 읽기 -> 성공시 콘솔 찍기 -> 실패시 err throw 하기
function readFileAsynchronously(filename) {
  fs.readFile(filename, 'utf-8', (err, data) => {
    if (err) throw err;
    console.log(data);
  });
  console.log('파일 읽기 요청 완료');
}

(👨🏻‍🏫 : 비동기 코드를 처음 접하면 실행 순서가 헷갈릴 수 있어요. 위 예제에서는 '파일 읽기 요청 완료'가 먼저 출력되고, 그 다음에 파일 내용이 출력된답니다. 신기하죠?)


3. 동기와 비동기의 장단점 비교

동기 방식의 장단점

장점:

  • 설계가 매우 간단하고 직관적이다.
  • 작업의 순서가 보장되어 예측 가능하다.
  • 디버깅이 상대적으로 쉽다.

단점:

  • 결과가 주어질 때까지 아무것도 못하고 대기해야 한다.
  • I/O 작업과 같이 시간이 오래 걸리는 작업에서 성능 저하가 발생할 수 있다.

비동기 방식의 장단점

장점:

  • 결과가 주어지는데 시간이 걸리더라도 그 시간 동안 다른 작업을 할 수 있어 자원을 효율적으로 사용할 수 있다.
  • I/O 작업이나 네트워크 요청과 같은 시간이 오래 걸리는 작업에 적합하다.
  • 사용자 인터페이스의 반응성을 유지할 수 있다.

단점:

  • 동기 방식보다 설계가 복잡하다.
  • 작업의 실행 순서가 보장되지 않아 예측하기 어려울 수 있다.
  • 디버깅이 어렵고 오류 처리가 복잡할 수 있다.

(👨🏻‍🏫 : 저는 처음에 비동기 프로그래밍을 배울 때 콜백 지옥에 빠졌었답니다. 프로미스와 async/await를 알기 전까지는 정말 고생했죠. 비동기의 장점이 많지만, 그만큼 잘 다루기 위한 학습 곡선이 있다는 점을 기억하세요!)


4. 동기와 비동기의 적절한 사용 상황

동기 처리가 적합한 경우

  • CPU 집약적인 작업: 복잡한 계산이나 데이터 처리와 같이 CPU를 많이 사용하는 작업.
  • 순서가 중요한 작업: 계좌 이체와 같이 작업의 순서가 중요한 경우.
  • 간단한 애플리케이션: 복잡성이 낮은 소규모 애플리케이션이나 스크립트.
  • 데이터 일관성이 중요한 경우: 데이터베이스 트랜잭션과 같이 일관성이 중요한 작업.

비동기 처리가 적합한 경우

  • I/O 작업: 파일 읽기/쓰기, 네트워크 요청, 데이터베이스 쿼리와 같은 I/O 작업.
  • 사용자 인터페이스: 사용자 경험을 향상시키기 위해 UI의 반응성을 유지해야 하는 경우.
  • 독립적인 여러 작업: 서로 의존성이 없는 여러 작업을 동시에 처리해야 하는 경우.
  • 대규모 서버 애플리케이션: 많은 요청을 동시에 처리해야 하는 웹 서버와 같은 애플리케이션.
// 비동기 처리의 좋은 예: 웹 API 요청
function fetchUserData() {
  console.log('데이터 요청 시작');
  fetch('<https://api.example.com/users>')
    .then(response => response.json())
    .then(data => {
      console.log('사용자 데이터:', data);
    })
    .catch(error => {
      console.error('에러 발생:', error);
    });
  console.log('다른 작업 계속 진행');
}

출처: MDN Web Docs https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API

(👨🏻‍🏫 : 실제 프로젝트에서는 동기와 비동기를 적절히 섞어서 사용하는 경우가 많답니다. 예를 들어, 서버에서는 비동기로 여러 요청을 처리하지만, 각 요청 내에서는 동기적으로 작업을 처리하는 식이죠!)


5. 실제 예제로 이해하는 동기와 비동기

일상생활에서의 예시 (동기식)

동기 방식: 은행 창구에서 업무를 보는 상황. 한 고객의 업무가 끝날 때까지 다른 고객은 기다려야 한다.

프로그래밍에서의 예시

동기 방식 코드 예제:

// 동기 방식의 계산 예제
function calculateSum(n) {
  let sum = 0;
  for (let i = 1; i  {
  console.log(`은행 손님 대접 ${i} 번째 손님`);
	}, 3000);
console.log('다음 작업 계속 진행'); // 타이머가 끝나기 전에 실행됨

출처: MDN Web Docs https://developer.mozilla.org/en-US/docs/Web/API/setTimeout

일상생황에서의 예시(비동기식)

비동기 방식: 카페에서 주문 후 진동벨을 받고 자리에 앉아 기다리는 상황. 주문 후 커피가 나오기를 기다리는 동안 다른 일을 할 수 있다.

프로그래밍에서의 예시

비동기 방식 코드 예제:

// 커피숍 비동기 작업 시뮬레이션
console.log("손님: 커피 한 잔 주세요.");

// 커피 준비 비동기 작업
const prepareCoffee = new Promise((resolve) => {
  console.log("바리스타1: 커피 준비 시작합니다.");
  setTimeout(() => {
    resolve("커피");
  }, 3000);
});

// 케이크 준비 비동기 작업
const prepareCake = new Promise((resolve) => {
  console.log("바리스타1: 케이크도 준비할게요.");
  setTimeout(() => {
    resolve("케이크");
  }, 2000);
});

console.log("손님: (자리에 앉아 Velog 확인 중)");

// 완료되는 즉시 비동기 작업 처리
prepareCoffee.then((coffee) => {
  console.log(`바리스타1: ${coffee} 나왔습니다.`);
});

// 완료되는 즉시 비동기 작업 처리
prepareCake.then((cake) => {
  console.log(`바리스타2: ${cake} 나왔습니다.`);
});

// 비동기들이 다 처리된 후처리
Promise.all([prepareCoffee, prepareCake]).then(() => {
  console.log("손님: 감사합니다!");
});

(👨🏻‍🏫 : JavaScript는 싱글 스레드 언어이지만, 비동기 처리를 통해 마치 멀티 스레드처럼 동작할 수 있답니다. 스레드가 작업의 개수를 나타내는데, 어떻게 이게 가능할까요? 이벤트 루프라는 개념이 이를 가능하게 하는데, 다음엔 이 주제로 글을 써보겠습니다!)

🙇🏻 글 내에 틀린 점, 오탈자, 비판, 공감 등 모두 적어주셔도 됩니다. 감사합니다..! 🙇🏻

profile
읽는 사람이 가장 이해하기 쉽게끔 적으려 노력합니다. 그 과정에서 스스로가 완전한 이해를 할 수 있다고 생각합니다. 그렇게 Taker 보다는 Giver이 되려 노력합니다.

0개의 댓글