CoreJavaScript Chapter 4. [callback function]

JUGNMIN LEE·2021년 5월 8일
0

CoreJavaScript

목록 보기
4/7
post-thumbnail

요번 챕터는 콜백함수에 대해 확인해보려 한다.
콜백함수는 최근 async await이나 promise등과 같이 비동기 처리가 나오기전에는 비동기 처리 문법으로 사용이 되었으며 그렇게 사용하는 단점으로는 콜백지옥이 나타난다
이러한 콜백을 면밀히 살펴 보려 한다.

CoreJavaScript

1. Callback Function 이란 ?

콜백함수는 간단하게 설명 한다면
단어 그대로 부르다 호출하다의 의미인 call과 뒤돌아오다 되돌다라는 의미인 back의 합성어로 "되돌아 호출해달라"라는 명령이다.

특정 함수 A를 호출하면서 '특정 조건일 때 함수 Y'를 실행해서 나에게 알려달라라는 요청을 보내는 것과 같다

이처럼 콜백함수는 특정 조건일때 실행할 Y라는 함수를 A에다가 제어권을 주는 것이다.


2. 콜백 함수는 ? 함수다 ~

콜백 함수는 함수다 이게 과연 무슨 말일까 ?

콜백 함수로 어떤 객체의 메서드를 전달할 때에도 그 메소드는 메소드가 아닌 함수로 호출이 된다.

아래의 코드를 확인해보자.

var obj = {
  vals: [1, 2, 3],
  logValues: function(v, i) {
    console.log(this, v, i)
  }
};
obj.logValues(1, 2);
//결과값 : { vals: [ 1, 2, 3 ], logValues: ƒ logValues() } 1 2
[4, 5, 6].forEach(obj.logValues);
//결과값 : window {...} 4 0
//결과값 : window {...} 5 1
//결과값 : window {...} 6 2

obj 객체의 메소드를 logValues로 설정해놓고
obj.logValues << 이렇게 불러왔으니 this는 obj를 가르키게 된다.

하지만 아래의 forEach를 보게 되면,
forEach에 의해 첫번째 인자값으로 콜백이 함수로써 호출이 되고 별도로 this를 지정하는 인자를 지정하지 않았기 때문에 함수 내부에서는 this는 전역 객체를 바라보게 된다.

즉! 어떤 함수의 인자에 객체의 메서드를 전달하더라도 이는 결국 메서드로 전달되는 것이 아닌 함수로써 호출이되는 것을 알고 있어야 한다.


3. 콜백 지옥과 비동기 제어

콜백 함수를 설명할때 꼭 필요한 내용이다 콜백 함수의 꽃.. ?
콜백지옥과 비동기 동기에 대한 간단한 개념을 알아보고 코드로 확인해보자.

콜백지옥

콜백 지옥은 콜백 함수를 익명 함수로 전달하는 과정이 반복되어 코드의 들여쓰기 수준이 감당하기 힘들 정도로 깊어지는 현상이다. 가독성이 떨어지면서 코드를 수정하기도 어렵다.

비동기와 동기

동기적인 코드는 현재 실행중인 코드에 대해 요청이 끝나고 그 다음 코드가 실행되는 방식이며 그 반대인 비동기는 현재 요청한 코드가 끝나기도 전에 다음 코드가 실행되는 방식이다.

현재 자바스크립트는 웹의 복잡도가 높아지고 통신이 많아지면서 비동기적인 코드가 많기 때문에 콜백 지옥에 빠지기도 쉽다

콜백지옥 예시 !!

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, '에스프레소');

이렇게 하면 코드의 가독성을 높일뿐 아니라 함수 선언과 함수 호출만 구분할 수 있다면 위에서부터 아래로 순서대로 읽어내려가는 데 어려움이 없게 된다 !!

또한 변수를 최상단으로 끌어올림으로써 외부에 노출을 시켰지만 전체를 즉시 실행 함수 등으로 감싸면 간단히 해결될 문제이다.


4. 그 외의 비동기 처리

콜백지옥과 같은 문제등으로 인해 요즘은 비동기 처리시 promise와 async, await등을 사용하게 된다.

해당 정리 글은 콜백함수에 대해 집중하고 있기 때문에
아래의 코드를 보면서 예시를 확인하고 넘어가자

1) 비동기 작업의 동기적 표현 - Promise

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

new 연산자와 함께 호출한 Promise의 인자로 넘겨주는 콜백 함수는 호출할 때에 바로 실행되지만 그 내부에 resolve 또는 reject 함수를 호출하는 구문이 있을 경우 둘 중 하나가 실행되기 전까지는 다음 또는 오류 구문으로 넘어가지 않는다!!

따라서 비동기 작업이 완료될 때 비로소 resolve 또는 reject을 호출하는 방법으로 비동기 작업의 동기적 표현이 가능하다.

2) 비동기 작업의 동기적 표현 - Promise + 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();

최근 ECMA에서는 가독성이 뛰어나면서 작성법도 간단한 async/await 문구가 추가 됬다! 비동기 작업을 수행하고자 하는 함수 앞에 async를 표시하고 함수 내부에서 실질적인 비동기 작업이 필요한 위치마다 await를 표기하는 것만으로 뒤의 내용을 Promise로 자동 전환이 되고, 해당 내용이 resolve된 이후에야 다음으로 진행이 된다 !



출처
모든 내용은 코어자바스크립트 공부를 하며 책 내용을 발췌해 이해한 내용들만 추려 적은 내용입니다 해당 코드들은 책 내용의 코드의 값들을 변경하거나 이해를 위해 그대로 가지고 왔습니다.

profile
Frontend Developer

3개의 댓글

comment-user-thumbnail
2021년 5월 8일

스터디 저 빼고 했습니까?

1개의 답글