본문 바로가기

WEB/HTML CSS JS

[JS] 비동기 처리 - Callback, Promise, async/await

바스크립트에는 비동기적으로 실행되는 함수들이 있다. (ex. setTimeout, AJAX를 활용한 라이브러리 함수들)
비동기 함수들은 실행순서를 제어해주지 않으면 코드의 실행 순서를 예측할 수 없고 코드의 가독성도 떨어진다.
비동기 함수들의 실행 순서를 제어하는 방법에는 어떤 것이 있는지 알아봤다.

Callback

  • 콜백함수는 다른 코드의 인자로 넘겨주는 함수로, 콜백 함수를 넘겨받은 코드는 이 콜백함수를 실행할 제어권을 가져 적절한 시점에 콜백 함수를 실행할 수 있게 된다.
  • 콜백지옥
setTimeout(
  function(name) {
    var Teletubbies = name;
    console.log(Teletubbies);

    setTimeout(
      function(name) {
        Teletubbies += ', ' + name;
        console.log(Teletubbies);

        setTimeout(
          function(name) {
            Teletubbies += ', ' + name;
            console.log(Teletubbies);

            setTimeout(
              function(name) {
                Teletubbies += ', ' + name;
                console.log(Teletubbies);
              },
              500,
              '뽀'
            );
          },
          500,
          '나나'
        );
      },
      500,
      '뚜비'
    );
  },
  500,
  '보라돌이'
);

실행 결과

보라돌이
보라돌이, 뚜비
보라돌이, 뚜비, 나나
보라돌이, 뚜비, 나나, 뽀

 

콜백 지옥에 빠지지 않는 방법

  • 각 스텝을 독립적인 함수로 만든다. 이전 스탭에서 error가 발생하지 않았을 경우 다음 단계의 함수를 실행하는 방식으로 코딩한다.
  • 그런데 promise 라는 더 좋은 방법이 있음.

 

Promise

  • Promise는 실행은 바로 하되, 결괏값은 나중에 받는 객체이다.
  • Promise 객체를 만드는 방법
const promise = new Promise(function(resolve, reject) { ... } );
  • 실제로는 변수에 할당하기 보다는 어떤 함수의 리턴값으로 바로 사용되는 경우가 많다.
function returnPromise() {
  return new Promise((resolve, reject) => { ... } );
}
  • Promise 객체 생성 후 resolve, reject를 매개변수로 갖는 콜백함수를 넣는다.
  • resolve 또는 reject가 실행되기 전까지는 then이나 catch 구문으로 넘어가지 않는다.
  • 따라서 비동기작업을 동기적으로 표현할 수 있다.

  • new Promise의 실행결과는 then을 붙였을 때 받게 된다.
  • then에서 다시 다른 then이나 catch를 붙일 수도 있다.
  • 이전 then의 리턴 값은 다음 then의 매개변수로 넘어간다.
  • Promise를 리턴하는 경우에는 프로미스가 수행된 후 다음 then이나 catch가 호출된다.
new Promise(function(resolve) {
  setTimeout(function() {
    var name = '보라돌이';
    console.log(name);
    resolve(name);
  }, 500);
})
  .then(function(prevName) {
    return new Promise(function(resolve) {
      setTimeout(function() {
        var name = prevName + ', 뚜비';
        console.log(name);
        resolve(name);
      }, 500);
    });
  })
  .then(function(prevName) {
    return new Promise(function(resolve) {
      setTimeout(function() {
        var name = prevName + ', 나나';
        console.log(name);
        resolve(name);
      }, 500);
    });
  })
  .then(function(prevName) {
    return new Promise(function(resolve) {
      setTimeout(function() {
        var name = prevName + ', 뽀';
        console.log(name);
        resolve(name);
      }, 500);
    });
  });

 

콜백 지옥 문제를 해결했음에도 Promise 가 갖고 있는 문제점

  • 수많은 then과 catch 때문에 여전히 코드가 깔끔하지 않다.
  • 여러개의 then 중 하나에서 오류가 발생하면 디버깅하기 어렵다.
  • try catch 문을 사용할 수 없다. catch() 메서드만을 이용해 예외처리를 해야한다.

 

async / await

  • async/await은 promise 를 더 쉽게 사용할 수 있는 방법이다.
  • async는 비동기적으로 함수를 실행시킨다. 그리고 항상 Promise를 반환한다.

  • 비동기 작업을 수행하고자 하는 함수 앞에 async를 표기하고,
  • 함수내부에서 실질적인 비동기 작업이 필요한 위치마다 await를 표기하면,
  • 뒤의 내용은 자동으로 Promise로 전환되고, 해당 내용이 resolve 된 이후에야 다음으로 진행한다.
var addMember = function(name) {
  return new Promise(function(resolve) {
    setTimeout(function() {
      resolve(name);
    }, 500);
  });
};

var television = async function() {
  var Teletubbies = '';
  var _addMember = async function(name) {
    Teletubbies += (Teletubbies ? ',' : '') + (await addMember(name));
  };
  await _addMember('보라돌이');
  console.log(Teletubbies);
  await _addMember('뚜비');
  console.log(Teletubbies);
  await _addMember('나나');
  console.log(Teletubbies);
  await _addMember('뽀');
  console.log(Teletubbies);
};

television();

 

+) axios.get(), fetch() 등의 함수는 API 호출 결과를 Promise로 리턴한다. 따라서 .then, .catch 메서드를 사용할 수 있다.

 

예시 코드 출처

  • 코어자바스크립트 ch4. 콜백 함수

 

참고 링크

 

 

'WEB > HTML CSS JS' 카테고리의 다른 글

Web 공부 리소스  (6) 2021.07.10
[JS] 코어자바스크립트 ch6. 프로토타입  (0) 2021.07.04
[JS] 코어자바스크립트 ch3. this  (0) 2021.07.03
[JS] 화살표함수  (0) 2021.07.02
[JS] 함수 선언문과 함수 표현식  (0) 2021.05.28