콜백함수 - callback function

콜백함수

콜백 함수란?

콜백 함수는 다른 코드의 인자로 넘겨주는 함수입니다. 콜백 함수를 넘겨받은 코드는 이 콜백 함수를 필요에 따라 적절한 시점에 실행합니다.
즉, 다른 코드(함수 또는 메서드)에게 인자로 넘겨줌으로써 그 제어권도 함께 위임한 함수입니다.

제어권

var count = 0;
var cbFunc = function () {
  console.log(count);
  if (++count > 4) clearInterval(timer);
};

var timer = setInterval(cbFunc, 300);

timer();

이 코드를 실행하게 되면 콘솔 창에는 0.3초마다 자동으로 실행 되며 count가 1씩 늘어나며 출력되다가 4가 출력된 이후 종료됩니다.
setInterval이라고 하는 '다른 코드'의 첫 번째 인자로 cbFunc 함수를 넘겨주자, 제어권을 넘겨받은 "setInterval" 함수는 스스로의 판단에 따라 적절한 시점에 cbFunc를 실행합니다. 이처럼 콜백함수의 제어권을 넘겨받은 코드는 콜백 함수 호출 시점에 대한 제어권을 가지게 됩니다.

콜백 지옥과 비동기 제어

콜백 지옥

콜백 함수를 익명 함수로 전달하는 과정이 반복되어 코드의 들여쓰기 수준이 감당하기 힘들 정도로 깊어지는 현상.
주로 이벤트 처리나 서버 통신과 같이 비동기적인 작업을 수행하기 위해 이런 형태가 자주 등장하게 됩니다.
콜백 지옥은 가독성이 떨어질뿐더러 코드를 수정하기도 어렵습니다.

동기적, 비동기적 코드

동기적인 코드

현재 실행 중인 코드가 완료된 후에야 다음 코드를 실행하는 방식.
CPU의 계산에 의해 즉시 처리가 가능한 대부분의 코드는 동기적인 코드입니다. 계산식이 복잡해 CPU가 계산하는 시간이 많이 필요한 경우라고 하더라도 동기적인 코드로 분류될 수 있습니다.

비동기적인 코드

현재 실행 중인 코드의 완료 여부와 무관하게 즉시 다음 코드로 넘어갑니다.
사용자의 요청에 의해 특정 시간이 경과되기 전까지 어떤 함수의 실행을 보류하거나, 직접적인 개입이 있기 전까지 어떤 함수를 실행하도록 대기하게 하거나, 웹 브라우저 자체가 아닌 별도의 대상에 무언가를 요청하고 그에 대한 응답이 왔을 때 다른 함수를 실행하도록 대기하는 등, 별도의 요청, 실행대기, 보류 등과 관련된 코드는 비동기적인 코드로 분류됩니다.

콜백 지옥을 해결하는 여러가지 방법

setTimeout(function (name) {
  var coffeeList = name;
  console.log(coffeeList);
  
  setTimeout(function (name) {
    coffeeList += ', ' + name;
    console.log(coffeeList);
    
    setTimeout(function (name) {
      coffeeList += ', ' + name;
      console.log(coffeeList);
      
      setTimeout(function (name) {
        coffeeList += ', ' + name;
        console.log(coffeeList);
      },500, '카페라떼');
    }, 500, '카페모카');
  }, 500, '아메리카노');
}, 500, '에스프레소');

기명 함수로 변환

var coffeeList = '';

var addEspresso = function (name) {
  coffeeList = name;
  console.log(coffeeList);
  setTimeout(addAmericano, 500, '아메리카노');
};

var addAmericano = function (name) {
  coffeeList += ', ' + name;
  console.log(coffeeList);
  setTimeout(addMocha, 500, '카페모카');
};

var addMocha = function (name) {
  coffeeList += ', ' + name;
  console.log(coffeeList);
  setTimeout(addLatte, 500, '카페라떼');
};

var addLatte = function (name) {
  coffeeList += ', ' + name;
  console.log(coffeeList);
};

setTimeout(addEspresso, 500, '에스프레소')

ES6 Promise의 사용 1

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)
  })
})

ES6 Promise의 사용 2

var addCoffee = function (name) {
  return function (prevName) {
    return new Promise(function (resolve) {
      setTimeout(function () {
        var newName = prevName ? (prevName + ', ' + name) : name;
        console.log(newName);
        resolve(newName);
      }, 500);
    });
  };
};

addCoffee('에스프레소')()
  .then(addCoffee('아메리카노'))
  .then(addCoffee('카페모카'))
  .then(addCoffee('카페라떼'))

ES6 Generator의 사용

var addCoffee = function (prevName, name) {
  setTimeout(function () {
    coffeeMaker.next(prevName ? (prevName + ', ' + name) : name);
  }, 500);
};

var coffeeGenerator = function* () {
  var espresso = yield addCoffee('', '에스프레소');
  console.log(espresso);
  
  var americano = yield addCoffee(espresso, '아메리카노');
  console.log(americano);
  
  var mocha = yield addCoffee(americano, '카페모카');
  console.log(mocha);
  
  var latte = yield addCoffee(mocha, '카페라떼');
  console.log(latte);
}

var coffeeMaker = coffeeGenerator();

coffeeMaker.next();

ES6 Promise + ES2017 async, await의 사용

var addCoffee = function (name) {
  return new Promise(function (resolve) {
    setTimeout(function () {
      resolve(name);
    }, 500);
  });
};

var coffeeMaker = async function () {
  var coffeeList = '';
  var _addCoffee = async function (name) {
    coffeeList += (coffeeList ? ',' : '') + await addCoffee(name);
  };
  
  await _addCoffee('에스프레소');
  console.log(coffeeList);
  
  await _addCoffee('아메리카노');
  console.log(coffeeList);
  
  await _addCoffee('카페모카');
  console.log(coffeeList);
  
  await _addCoffee('카페라떼');
  console.log(coffeeList);
};

coffeeMaker();

좋은 웹페이지 즐겨찾기