<Web> Asynchronous (callback, promise, await)

Google 아니고 Joogle·2022년 9월 10일
0

web

목록 보기
6/7

javascript에서 비동기를 공부하기 전에 헷갈리는 sync, async, blocking, non-blocking에 대해 간단하게 정리하고 시작한다

1. Asynchronous ?

Synchronous == Blocking ? Asynchronous == Non-blocking?

동기와 비동기, blocking과 non-blocking은 각각 관심을 갖는 부분이 다르다

Sync / Async

  • 동기와 비동기는 호출되는 함수의 완료를 호출한 쪽에서 신경을 쓰냐, 호출 받은 쪽에서 신경을 쓰냐 차이다
  • 동기는 요청과 그 결과가 동시에 일어난다는 뜻이며, 어떤 객체 또는 함수 내부에서 다른 함수를 호출했을 때, 이 함수의 결과를 호출한 쪽에서 처리하면 동기
  • 비동기는 요청과 그 결과가 동시에 일어나지 않는다는 뜻이며, 동기와 달리 어떤 객체 또는 함수 내부에서 다른 함수를 호출했을 때 이 함수의 결과를 호출한 쪽에서 처리하지 않으면 비동기 (호출된 함수가 작업 완료를 신경씀, callback을 통한 처리)

Blocking / Non-blocking

  • Blocking은 호출받은 쪽이 호출한 쪽에 제어권을 넘겨주지 않는 것이고 Non-blocking은 다시 제어권을 넘겨주는 것
  • blocking은 자신의 수행결과가 끝날 때까지 제어권을 갖고 있는 것을 의미
  • Non-blocking은 자신이 호출되었을 때 제어권을 바로 자신을 호출한 쪽으로 넘기며, 자신을 호출한 쪽에서 다른 일을 할 수 있도록 하는 것을 의미

2. JavaScript에서 Async

자바 스크립트에서 비동기화를 처리하는 방법에는 여러 가지가 있고, 아래에서 callback, promise, await를 차례대로 살펴본다

비동기 작업 수행

  • 비동기 작업을 수행하는 간단한 예를 살펴보자
  • setTimeout functionsetTimeout(function, 시간)과 같은 구조를 가지고, 시간/1000초 후에 function을 수행한다
  let data=[1,2,3];

  function getData() {

  setTimeout( () => {
      data.push(4);
      data.push(5);

      console.log("done!");
      printData();
      }, 1000);
  }

  function printData() {
      data.forEach(el => console.log(el));
  }

  getData();
  printData();
  • getDate(), printDate()를 차례대로 호출했을 때, setTimeout안에 있는 4,5를 push하는 과정이 일어나기 전에 printDate()가 먼저 수행되어 1,2,3이 출력되고 그 후에 4,5의 push가 일어남을 확인할 수 있다

callback

callback함수는 간단하게 다른 함수에 매개변수로 넘겨준 함수를 말한다. 매개변수로 넘겨받은 함수는 일단 넘겨받고, 때가 되면 나중에 호출 (called back)한다는 것이 콜백함수의 개념이다
(참고로 JavaScript의 함수는 일급 객체로, 매개변수로 전달될 수 있다는 특징이 있다)

  • 아래와 같은 예에서 결과값을 이용해서 처리할 로직을 (4,5를 push한 후, data를 print하는 것) 콜백 함수에 담아 인자로 던진다
  let data=[1,2,3];

  function getData( callback ) {

      setTimeout( () => {
      data.push(4);
      data.push(5);

      console.log("done!");
      callback ();
      }, 1000);
  }

  function printData() {
      data.forEach(el => console.log(el));
  }
  getData(printData);
  • setTimeout의 작업이 모두 끝나면 callback을 수행하는 것을 볼 수 있다

Promise

  • JavaScript 프로젝트가 점점 더 복잡해지면서 콜백 함수로 인자를 넘겨서 비동기 처리를 하는 스타일은 피하고 있다
    (콜백함수를 중첩해서 사용하게 되면 계속해서 코드를 들여쓰기 해야하고, 코드의 가독성이 떨어지기 때문)
  • 아래 코드에서 getDate()가 호출되었을 때, 에러가 없다면 resolve, 있다면 reject를 실행한다
  • 에러가 없다면 printDate()를, 에러가 있다면 'Error'를 출력하는 형태이다
  let data=[1,2,3];

  function getData() {

    /*
    비동기 작업이 성공하면 resolve
    비동기 작업이 실패하면 reject
    */

      return new Promise( (resolve, reject) => {

      setTimeout( () => {
          data.push(4);
          data.push(5);

          console.log("Done!");

          const error=false;
          if (!error) resolve();
          else reject('Error!');

      }, 1000);
      });
  }

  function printData() {
      data.forEach(el => console.log(el));
  }
  • 실행코드는 아래와 같다. getDate()를 호출하였을 때 성공하면 printDate를, 실패하면 반환되는 에러 메시지를 출력하는 형태이다
  getData()
      .then(printData)
      .catch(e=>console.log(e));

Promise 기반의 Await

  • asyncawait를 사용하여 Promise를 좀 더 편하게 사용하기 위함이다
  • await 키워드를 만나면 promise가 처리될 때까지 기다리고, 결과는그 이후에 반환된다
  • promise가 처리되길 기다리는 동안엔 엔진이 다른 일 (다른 스크립트 실행, 이벤트 처리 등)을 할 수 있기 때문에 CPU 리소스가 낭비되지 않음
  • 앞에서 작성했던 Promise의 예시에서 .then의 호출을 await로, function앞에 async를 붙여 await를 사용할 수 있도록 한다
  let data=[1,2,3];

  function getData() {
      return new Promise( (resolve, reject) => {

      setTimeout( () => {
      data.push(4);
      data.push(5);

      console.log("Done!");

      const error=false;

      if (!error) resolve();
      else reject('Error!');

      }, 1000);
      });
  }

  function printData() {
      data.forEach(el => console.log(el));
  }

  doIt();

  async function doIt () {
      await getData();  //promise 기반 비동기 function -> 이게 끝나면 다음 라인 수행
      printData();
  }
  • 에러를 핸들링하기 위해 try...catch를 사용할 수도 있다
  async function doIt () {
      try {
          await getData();  
          printData();
      } catch (e) {
          console.log(e);
      }          
  }

Reference

profile
Backend 개발자 지망생

0개의 댓글