4 콜백 함수
콜백 함수
콜백 함수란 다른 함수의 인자로 전달되는 함수를 말한다.
이렇게 다른 함수에 함수를 함께 전달해서, 특정한 상황에서 그 함수를 실행해달라 요청하는 것이다. 그 함수의 제어권을 넘긴다고 할 수 있다.
제어권
- 콜백 함수의 제어권을 받은 코드는 콜백 함수 호출 시점에 대한 제어권을 갖는다. 그 콜백 함수를 언제 호출할 것이냐는 전적으로 제어권을 받은 코드에 달려 있다.
- 콜백 함수에 인자를 넣어서 호출하는 쪽은 콜백 함수의 제어권을 받은 쪽이다. 따라서 인자 순서에 대한 제어권도 갖는다. (마음대로 map에 전달하는 콜백 함수 인자를
(index, value)로 변경해서는 안 된다.)
콜백 함수와 this
콜백 함수를 받는 함수들 중에는 thisArg 같은 인자로 콜백 함수를 실행할 때 적용할 this를 함께 인자로 받는 함수들이 있다. (참고 : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array#iterative_methods) 이런 함수들은 내부에서 call/apply 메서드를 이용해서 thisArg로 받은 값이 있다면 그 값을, 아니면 전역객체를 바인딩하는 식으로 동작한다.
콜백 함수는 어떤 함수를 전달하더라도 함수로서 호출된다. 메서드를 전달하더라도 받는 입장에서는 그 프로퍼티에 담긴 함수 값을 받은 것이 된다. 따라서 메서드를 전달하든, 일반 함수를 전달하든 기본적으로 함수로서 호출된다.
그렇다면 만약에 thisArg를 받지 않는 함수의 경우에는 어떻게 this를 바인딩할 수 있을까? 두 가지 방법이 있다.
첫 번째는 전통적 방법이다. this를 다른 변수에 담아서 콜백 함수에서 this 대신 그 변수를 사용하게 하고, 이걸 클로저로 만드는 방식이다.
var obj1 = {
name: 'obj1',
func: function() {
var self = this; // obj
return function () {
console.log(self.name); // this 대신 self를 사용한다.
}
}
}
var callback = obj1.func();
setTimeout(callback, 1000); // obj1 출력근데 이 방식은 번거롭기도 하고 메모리를 낭비한다는 단점이 있다.
그래서 ES5에서 이 단점을 해결할 수 있는 두 번째 방법, bind 메서드가 등장했다. this를 따로 저장할 필요도 없고 재사용도 용이하다.
var obj1 = {
name: 'obj1',
func: function() {
return function () {
console.log(this.name);
}
}
}
setTimeout(obj1.func.bind(obj1), 1000); // this에 obj1을 명시적으로 연결
var obj2 = {name: 'obj2'};
setTimeout(obj1.func.bind(obj2), 1000); // 재사용도 가능콜백 지옥 / 비동기
콜백이 중첩되어서 가독성이 떨어지고 에러 처리가 곤란하고 코드 수정도 어려워지는 문제 상황을 콜백 지옥이라고 한다. 주로 비동기 작업을 수행할 때 콜백을 익명 함수로 전달하는 과정이 반복되면서 발생하는 현상이다.
이 문제를 해결하기 위한 방법이 지속적으로 등장했는데 ES6에서는 Promise와 Generator, ES2017에서는 async/await이 등장했다. (책에서는 간단히 소개하는 것으로 마무리됐다.)