soowanlog

동기, 비동기 본문

프론트엔드/Javascript

동기, 비동기

개발자솬
프론트엔드/Javascript

동기, 비동기

개발자솬 2024. 3. 11. 23:24
728x90
반응형
  • 동기, 비동기란?

 

- 동기(Synchronous)란 직렬적으로 태스크를 수행하는 방식입니다.

즉, 요청을 보낸 후 응답을 받아야지만 다음 동작이 이루어지는 방식으로 하나의 작업이 완료될 때까지 다음 코드의 실행을 멈추고 기다리는 것을 의미합니다.

 

- 비동기(Asynchronous)란 병렬적으로 태스크를 수행하는 방식입니다.

즉, 요청을 보낸 후 응답 여부와 관계없이 다음 동작이 이루어지는 방식으로 하나의 작업이 완료되지 않았더라도 다음 코드를 실행하는 것을 의미합니다.

비동기 요청 시 응답 후 처리할 콜백 함수를 함께 알려주어 해당 태스크가 완료되었을 때 콜백 함수가 호출됩니다.

하지만 비동기 처리를 위해 콜백 패턴을 사용하게 되면 처리 순서를 보장하기 위해 여러 개의 콜백 함수가 중첩되어 복잡도가 높아지는 콜백 헬이 발생하는 단점이 있습니다.

※ Javascript에서의 비동기 처리


Javascript는 싱글 스레드 기반의 프로그래밍 언어이기 때문에 이전 작업이 완료될 때까지 다음 작업을 처리할 수 없음. 이러한 문제점을 해결하기 위해 Javascript에서는 비동기 처리가 필요함.

Javascript에서 비동기 처리를 위한 하나의 패턴으로 콜백 패턴이 있지만 콜백 헬 등 여러 한계가 있어 또 다른 패턴으로 Promise와 async / await가 등장함.

 

  • Promise란?

Promise란 Javascript에서 비동기 처리를 위한 콜백 패턴의 단점을 보완하여 사용되는 객체입니다.

Promise는 객체이기 때문에 생성자 함수를 호출하여 인스턴스화할 수 있는데 이때 resolve와 reject 함수를 인자로 전달받는 콜백 함수를 인자로 전달받습니다.

Promise는 인자로 전달받은 콜백 함수를 내부에서 비동기 처리합니다.

const promise = () => new Promise((resolve, reject) => {
  let a = 1 + 1;
  
  if (a == 2) {
    resolve('맞습니다.');
  } else {
    reject('틀립니다.');
  }
});

그다음 Promise의 후속 처리 메서드인 then(), catch()를 통해 비동기 처리 결과 메시지를 전달받아 처리합니다.

후속 처리 메소드는 다시 Promise객체를 반환합니다.

promise().then((message) => {
  console.log('결과가 ' + message);
}).catch((message) => {
  console.log('결과가 ' + message);
});
// 결과가 맞습니다.

 

  • Promise의 에러 처리 방법

- then 메서드의 두 번째 인자로 예외를 처리하는 방법

const promise = () => new Promise((resolve, reject) => {
  let a = 1 + 1;
  
  if (a == 3) {
    resolve('맞습니다.');
  } else {
    reject('틀립니다.');
  }
});

promise().then((message) => {
  console.log('결과가 ' + message);
}, (error) => {
  console.log('결과가 ' + error);
});
// 결과가 틀립니다.

두 번째 인자로 예외를 처리하는 경우 첫 번째 콜백함수에서 발생한 에러를 두 번째 콜백함수가 잡아내지 못할 수 있습니다.

const promise = () => new Promise((resolve, reject) => {
  let a = 1 + 1;
  
  if (a == 2) {
    resolve('맞습니다.');
  } else {
    reject('틀립니다.');
  }
});
 
promise().then((message) => {
  console.log('결과가 ' + message);
  thro new Error('틀립니다.');
}, (error) => {
  console.log('결과가 ' + error);
});
// 결과가 맞습니다.
// (node:52580) UnhandlePromiseRejectionWraning: Error: 틀립니다.

 

- catch 메서드를 이용하여 예외를 처리하는 방법

const promise = () => new Promise((resolve, reject) => {
  let a = 1 + 1;
  
  if (a == 3) {
    resolve('맞습니다.');
  } else {
    reject('틀립니다.');
  }
});

promise().then((message) => {
  console.log('결과가 ' + message)
}).catch((error) => {
  console.log('결과가 ' + error)
});
// 결과가 틀립니다.

catch 메서드를 사용할 경우 then 메서드의 첫 번째 콜백함수에서 발생하는 에러를 처리할 수 있습니다.

const promise = () => new Promise((resolve, reject) => {
  let a = 1 + 1;
  
  if (a == 2) {
    resolve('맞습니다.');
  } else {
    reject('틀립니다.');
  }
});
 
promise().then((message) => {
  console.log('결과가 ' + message);
  thro new Error('틀립니다.');
}).catch((error) => {
  console.log('결과가 ' + error);
});
// 결과가 맞습니다.
// 결과가 틀립니다.

 

  • Promise 체이닝

비동기 함수의 처리 결과를 가지고 다른 비동기 함수를 호출하는 경우 함수의 호출이 중첩되어 콜백 헬이 발생할 수 있습니다.

Promise의 후속 처리 메서드는 Promise객체를 반환 하기때문에 체이닝 하여 여러 개의 비동기 함수들을 연결하여 사용할 수 있습니다.

const promise = (num) => {
  return new Promise((resolve, reject) => {
    if (num == 1) {
      resolve('맞습니다.');
    } else {
      reject('틀립니다.');
    }
  });
});

promise(1)
  .then((message) => promise(message))
  .then((message) => console.log('결과가 ' + message))
  .catch((error) => console.log('결과가 ' + error));
// 결과가 틀립니다.

 

 

  • async / await란?

async와 await는 Javascript의 비동기 처리 패턴 중 가장 최근에 등장한 패턴입니다.

async와 await를 사용하면 비동기 코드를 동기 코드처럼 작성할 수 있어 가독성이 좋아지고 에러 처리가 간단해집니다.

 

- async :

async 키워드는 function 앞에 사용하고 해당 함수는 항상 Promise를 반환합니다.

Promise가 아닌 값을 반환하더라도 Resolved Promise(이행 상태의 프라미스)로 값을 감싸 Resolved Promise가 반환되도록 합니다.

async function num() {
  return 1;
};

num().then(res => console.log(res));
// 1

위 함수에 1을 Promise.resolve() 로 감싸도 같은 결과를 반환합니다.

async function num() {
  return Promise.resolve(1);
};

num().then(res => console.log(res));
// 1

즉, async가 붙은 함수는 반드시 Promise를 반환하고 Promise가 아닌 것은 Resolved Promise로 감싸서 반환합니다.

 

- await:

await는 async 함수 안에서만 동작합니다.

Promise가 처리될 때까지 기다린 후에 결과를 반환합니다.

async function add() {
  const promise = new Promise((resolve, reject) => {
    setTimeout(() => resolve("1 + 1 = 2"), 1000);
  });
  
  let result = await promise;
  
  console.log(result);
};

add();
// 1 + 1 = 2

위의 예제에서 Promise는 1초 뒤에 처리되기 때문에 Promise의 결과는 변수 result에 1초 뒤에 할당되어 콘솔에 출력됩니다.

await는 Promise가 처리될 때까지 함수 실행을 기다리게 만들기 때문에 Promise가 처리되길 기다리는 동안 엔진이 다른 일을 할 수 있기 때문에 CPU 리소스가 낭비되지 않습니다.

 

  • async / await의 에러 처리 방법

await가 던진 에러는 throw가 던진 에러를 잡을 때 처럼 try, catch를 사용해 잡을 수 있습니다.

async function div(num) {
  try {
    let result = await new Promise((resolve, reject) => {
      if (num == 0) {
        reject('0으로 나눌 수 없습니다.');
      } else {
        resolve(10 / num);
      }
    });
    console.log(result);
  } catch (error) {
    console.log(error);
  }
}

div(0);
// 0으로 나눌 수 없습니다.

참    고    자    료

- async / await 개념 정리 (Feat. 동기, 비동기) | kohigowild

 

- 동기, 비동기란? (+Promise, async/await 개념) | khy__.log

 

- 프로미스(Promise)란 | 박만자

 

728x90
반응형

'프론트엔드 > Javascript' 카테고리의 다른 글

Ajax  (0) 2024.03.11
Javascript  (0) 2024.03.09