ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [JavaScript] 비동기 처리 : Callback, Promise, Async/Await
    카테고리 없음 2020. 3. 22. 19:27

     

     

    바르셀로나 스타일이라고 하면 티키타카로 대표되는 패스 축구를 가장 먼저 떠올릴 것이다. 바르셀로나의 더운 날씨로 인해서 직접 뛰기보다는 패스로 공을 운반하는 티키타카 스타일이 자리 잡게 되었다고 한다. 골키퍼부터 시작해서 최전방 공격수까지 이어져 골을 만들어 내는 모습은 감탄스럽다. 

    골키퍼가 피케에게 공을 패스한다. 피케는 1초 뒤에 부스케츠에게 공을 패스한다. 부스케츠는 1초 뒤 호르디 알바에게, 알바는 1초 뒤 그리즈만에게, 그리즈만은 1초 뒤 메시에게 패스한다. 그리고 1초 뒤 메시가 득점한다. 이를 코드를 통해 짜 보면 어떻게 될까?

    포인트는 모든 동작들이 1초의 텀을 두고 이루어진다는 것이다. 이 경우 setTimeOut 함수를 이용할 수 있다. 비동기로 이루어진다. 패스 순서를 정확하게 맞추기 위해서는 비동기함수들이 정해진 순서대로, 마치 동기 함수처럼 작동해야 한다. 

    1. 콜백 (Callback)

    // callback
    var pass = function(name) {
      console.log(`pass ${name} the ball!`);
    };
    
    setTimeout(() => {
      console.log("pass Pique the ball");
      setTimeout(() => {
        console.log("pass Busquets the ball");
        setTimeout(() => {
          console.log("pass Jordi the ball");
          setTimeout(() => {
            console.log("pass Griezman the ball");
            setTimeout(() => {
              console.log("pass Messi the ball");
              setTimeout(() => {
                console.log("Messi scores!");
              }, 1000);
            }, 1000);
          }, 1000);
        }, 1000);
      }, 1000);
    }, 1000);

    먼저 콜백을 이용한 해결방법을 생각해볼 수 있다. 콜백을 사용해 실행 순서를 지정해줄 수 있다. 위와 같이 코드를 작성하면 의도한 순서대로 1초 텀으로 패스가 이루어진다.

    하지만 패스의 수가 늘어날수록 콜백도 늘어나게 된다. 흔히 말하는 '콜백 지옥'에 빠지게 되는 것이다. 콜백 지옥은 가독성을 해치고 유지 관리를 어렵게 만든다. 

    2. 프로미즈 (Promise)

    // promise
    var passDelay = () => {
      return new Promise(resolve => {
        setTimeout(() => {
          resolve();
        }, 1000);
      });
    };
    
    function passPromise() {
      console.log("pass Pique the ball");
      return passDelay();
    }
    
    passPromise()
      .then(() => {
        console.log("pass Busquets the ball!");
        return passDelay();
      })
      .then(() => {
        console.log("pass Jordi the ball!");
        return passDelay();
      })
      .then(() => {
        console.log("pass Griezman the ball!");
        return passDelay();
      })
      .then(() => {
        console.log("pass Messi the ball");
        return passDelay();
      })
      .then(() => {
        console.log("Messi scores!");
      });

    이를 보완하기 위해 프로미즈(Promise)를 사용할 수 있다. 프로미즈를 생성해 이를 리턴하고 이를 계속 then() 으로 이어나가 작업을 순차적으로 처리하는 것이 가능하다. 콜백 방식을 사용하는 것보다 훨씬 가독성이 좋아졌음이 느껴진다. 

    하지만 여전히 같은 논리로, 프로미즈가 계속 이어진다면 프로미즈 지옥에 빠지게 되는 것은 아닐까?

    3. Async/Await

    Async/Await 은 비동기를 처리하기 위한 더욱 간단한 해결방법이다. 일반 함수 앞에 async 를 붙여주면 해당 함수는 프로미즈를 리턴하는 함수가 된다. 

    // async/await
    var passAwait = () => {
        return new Promise(resolve => {
            setTimeout(() => { resolve()}, 1000);
        })
    };
    
    var asyncPass = async () => {
      console.log("pass Pique the ball!");
      await passAwait();
      console.log("pass Busquets the ball!");
      await passAwait();
      console.log("pass Jordi the ball!");
      await passAwait();
      console.log("pass Griezman the ball!");
      await passAwait();
      console.log("pass Messi the ball!");
      await passAwait();
      console.log("Messi scores!");
    };
    
    asyncPass();

     

    위 코드는 기존 코드에 Async/Await 을 적용한 방법이다. 마치 일반적인 동기 함수를 쓰는 것 같이 직관적이다. 위 코드를 실행하면 우리가 처음 의도했던 것처럼 피케부터 메시까지 1초 간격으로 패스가 이어지는 것을 콘솔을 통해 확인할 수 있다. 

     

    * Reference : 캡틴판교(https://joshua1988.github.io/web-development/javascript/js-async-await/), 

    개발자 황준일 블로그( http://junil-hwang.com/blog/javascript-promise-async-await/),

    댓글