동기 방식(Sync.) vs. 비동기 방식(Async.)

vvinter·2024년 4월 11일
0

개발용어

목록 보기
26/28

동기와 비동기?

데이터 처리 모델은 데이터를 받는 방식으로 동기, 비동기의 2가지 처리 모델이 존재한다.

🎲   동기(synchronous)

  • 직렬적으로 작업을 수행하는 방식
  • 요청을 보낸 후 응답받아야만 다음 동작으로 진행
    ⇒ 하나의 작업을 처리하는 동안 나머지 작업은 대기
  • 장단점
    • 장점 : 설계가 매우 간단하고 직관적임
    • 단점 : 응답받을 때까지 아무것도 못 하고 대기해야 하므로, 시스템 전체 효율이 저하될 수 있음

🎲   비동기 (asynchronous)

  • 병렬적으로 작업을 수행하는 방식
  • 요청을 보낸 후 응답의 여부와는 상관없이 다음 동작으로 진행
    ⇒ 하나의 작업이 실행되는 동안 다른 작업을 실행 가능
  • 비동기 요청 시, 응답 후 처리할 ‘콜백 함수’를 함께 알려줌. 따라서 해당 작업이 완료되면, 콜백 함수가 호출됨
    • 비동기 처리를 위해 중첩하여 콜백 패턴을 사용하면 여러 개의 콜백 함수가 중첩되어 복잡도가 높아지는 콜백 지옥(콜백 헬, Callback Hell)이 발생하는 단점 존재.
  • 장단점
    • 장점 : 요청에 따른 응답이 반환되는 시간 동안 다른 작업 수행 가능 ⇒ 효율적인 자원 사용 가능
    • 단점 : 동기식보다 설계 복잡

동기와 비동기의 작업 방식 차이

(출처 : https://jieun0113.tistory.com/73)


🔎  Callback 함수

콜백함수란 함수에 매개변수로 함수 객체를 전달해서 호출 함수 내에서 매개변수 함수를 실행하는 것을 뜻하며, 다른 함수가 실행을 끝낸 뒤 실행된다.
콜백함수는 가독성이나 코드 재사용 면에서도 사용되며, 비동기 방식으로 작성된 함수를 동기 처리하기 위해서도 사용된다.


블록과 논블록

🧩  블록 Block

  • 호출된 함수가 자신이 할 일을 모두 마칠 때까지 제어권을 계속 가지고서 호출한 함수에 바로 리턴하지 않는 것
  • A라는 함수를 실행했을 때, A라는 함수가 모든 행위를 끝마칠 때까지 기다렸다가 다른 함수가 실행되면 이것은 블로킹 되었다고 함.

🧩  논블록 Non-Block

  • 호출된 함수가 자신이 할 일을 마치지 않았더라도 바로 제어권을 리턴하여 호출한 함수가 다른 일을 진행할 수 있도록 하는 것
  • 만약 A라는 함수를 호출했는데, A라는 함수의 로직이 끝나기도 전에 B라는 함수가 실행된다면 이것은 논블로킹 되었다고 함.

(출처 : https://dkswnkk.tistory.com/488)


Promise

자바스크립트는 비동기 처리를 위한 하나의 패턴으로 콜백 함수를 사용한다. 하지만 전통적인 콜백 패턴은 콜백 지옥(콜백 헬)로 인해 가독성이 나쁘고 비동기 처리 중 발생한 에러의 처리가 곤란하며, 여러 개의 비동기 처리를 한 번에 처리하는 데도 한계가 있다. 그래서 ES6에서는 비동기 처리를 위한 또 다른 패턴으로 프로미스(Promise)를 도입했다.

  • 프로미스는 비동기 처리를 실행하고 비동기 처리가 끝난 다음 코드를 순차적으로 실행하기 위해 사용
  • 프로미스를 사용하기 위해서는 프로미스 객체를 생성해야 함.
  • 전통적인 콜백 패턴이 가진 단점을 보완하며 비동기 처리 시점을 명확하게 표현할 수 있음.

➡️  콜백 지옥을 경험하고 나서 등장한 것도 있지만, 프로미스는 보통 네트워크 통신이나 파일에서 큰 데이터를 읽는 등의 무거운 작업을 수행할 때 많이 사용한다.

// Promise 객체의 생성
const promise = new Promise((resolve, reject) => {
  // 비동기 작업을 수행한다.

  if (/* 비동기 작업 수행 성공 */) {
    resolve('result');
  }
  else { /* 비동기 작업 수행 실패 */
    reject('failure reason');
  }
});

→ 프로미스는 Promise 생성자 함수를 통해 객체 생성, Promise 생성자 함수는 비동기 작업을 수행할 콜백 함수를 인자로 전달받는다.
→ 프로미스는 실패할 때도 존재하기 때문에 성공할 경우는 resolve에, 실패할 경우는 reject에 리턴할 값과 에러 메시지를 담는다. (if 절로 분기를 나눠서 정리)
⇒ 실패한 경우에 에러 메시지는 프로미스 객체의 후속 처리 메소드로 전달됨.

📍  프로미스의 상태 정보

  • pending: 비동기 처리가 아직 수행되지 않은 상태
  • fulfilled: 비동기 처리가 수행된 상태 (성공)
  • rejected: 비동기 처리가 수행된 상태 (실패)
  • settled: 비동기 처리가 수행된 상태 (성공 또는 실패)

📍  후속 처리 메소드

  • then
    • 두 개의 콜백 함수를 인자로 전달받음.
    • 첫 번째 콜백 함수는 성공 시 호출, 두 번째 함수는 실패 시 호출
    • then 메소드는 프로미스를 반환
  • catch
    • 예외(비동기 처리와 then 메소드에서 발생한 에러)가 발생하면 호출됨.
    • catch 메소드는 프로미스 반환
  • finally
    • 성공, 실패 여부와 상관없이 실행하고 싶은 기능을 호출
promise
  .then((value) => {
    console.log(value);
  })
  .catch((error) => {
    console.log(error);
  })
  .finally(() => {
    console.log("anyway finally");
  });

📍  프로미스 체이닝

프로미스는 후속 처리 메소드를 체이닝하여 여러 개의 프로미스를 연결하여 사용할 수 있는데 이를 이용하여 콜백 지옥을 해결할 수 있다.


Async / Await

자바스크립트의 비동기 처리 패턴 중 가장 최근에 나온 문법으로, 기존의 비동기 처리 방식인 콜백 함수와 프로미스의 단점을 보완하고 가독성 좋은 코드를 작성할 수 있게 도와준다.

async function 함수명() {
  await 비동기처리_메서드_명();
}

🎲  async 

  • function 앞에 사용
  • async가 붙은 함수는 반드시 프로미스를 반환하고, 프로미스가 아닌 것은 프로미스(이행된 상태의 프로미스 Promise.resolve())로 감싸 반환

🎲  await

  • async 함수 안에서만 동작
  • 프로미스가 처리될 때까지 기다리는 역할을 하며, 프로미스가 처리되면 그 결과와 함께 실행이 재개됨.
  • await가 던진 에러는 try … catch를 사용해 처리할 수 있음

💡 async/await를 사용하면 await가 대기를 처리해 주기 때문에 .then(프로미스)이 거의 필요하지 않으며, 일반 try … catch를 사용할 수 있어서 대개는 async/await를 사용하는 것이 편하다.

그러나, await는 async 안에서만 동작하기 때문에 관행처럼 .then/catch를 추가해 최종 결과나 처리되지 못한 에러를 다룬다.






📎  참고

https://jieun0113.tistory.com/73
https://velog.io/@slobber/동기와-비동기의-차이
https://velog.io/@khy226/동기-비동기란-Promise-asyncawait-개념
https://dkswnkk.tistory.com/488
https://lunuloopp.tistory.com/entry/동기-비동기의-이해-callback함수-promise-async-await
https://velog.io/@ko1586/Callback함수란-뭔데
https://velog.io/@wnduf8922/JS-Promisethen-catch

0개의 댓글