CallBack에 뜻은 call(부르다, 호출하다, 실행하다) + back (뒤돌아오다, 뒤돌다) 되돌아 호출하는 함수.
= 함수 X를 호출하면서 특정 조건일 때 함수 Y를 실행해서 나에게 알려달라고 명령하는 것
= 함수X는 해당 조건이 갖춰졌는지 여부를 스스로 판단하고 Y를 직접 호출한다
콜백 함수의 제어권을 넘겨받은 코드는 콜백 함수 호출 시점에 대한 제어권을 가짐
콜백 함수도 함수이기 떄문에 기본적으로는 this가 전역객체를 참조하지만, 제어권을 넘겨받을 코드에서 콜백 함수에 별도로 this가 될 대상을 지정한 경우에는 그 대상을 참조하게된다.
콜백 함수로 어떤 객체의 메서드를 전달하든 그 메서드는 메서드가 아닌 함수로서 호출된다.
var obj = {
vals: [1, 2, 3],
logValues: function(v, i) {
console.log(this, v, i);
}
};
obj.logValues(1, 2); // Output : { vals: [1, 2, 3], logValues: f } 1 2
// obj의 메서드로 정의되어, 메서드로서 호출
[4, 5, 6].forEach(obj.logValues); // Output : Window{ . . .} 4 0
// 메서드로 정의되어있지만, 콜백 함수로 전달되었기 때문에 함수로서 호출된다.
객체의 메서드를 콜백 함수로 전달하면 해당 객체를 this로 바라볼 수 없다.” 라고 했다. 하지만, 그럼에도 콜백 함수 내부의 this가 객체를 바라보게 하고싶다면, 전통적인 방법으로 this를 다른 변수에 담아, 콜백 함수로 활용할 함수에서는 this 대신 그 변수를 사용하게 하고, 이를 클로저로 만드는 방식을 쓴다.
콜백 함수 내부의 this에 다른 값을 바인딩하는 방법(전통적인방법)
var obj1 = {
name: 'obj1',
func: function() {
var self = this;
return function() {
console.log(self,name);
};
}
};
var callback = obj1.func();
setTimeout(callback, 1000);
// 위 코드는 '실제로' this를 사용하지도 않을뿐더러 너무 번거롭고 비효율적이다.
콜백 함수 내부에서 this를 사용하지 않은 경우
var obj1 = {
name : 'obj1',
func : function() {
console.log(obj1.name);
}
};
setTimeout(obj1.func, 1000);
// 위 전통적인 방법의 코드보다는 간결하고 직관적인 개선 부분이 있지만, 작성함 함수를 this를 이용해 다양한 상황에 재활용할 수 없다는 단점이 있다.
bind 메서드 이용한 콜백 함수 내부의 this에 다른 값을 바인딩하는 방법
var obj1 = {
name: 'obj1',
func: function() {
var self = this;
return function() {
console.log(self,name);
};
}
};
setTimeout(obj1.func.bind(ob1), 1000);
var obj2 = { name: 'obj2'};
setTimeout(obj1.func.bind(obj2), 1000);
현재 실행중인 코드의 완료 여부와 무관하게, 즉시 다음코드로 넘어가는 실행 방식.
자바스크립트에서 별도의 요청, 실행 대기, 보류 등과 관련된 코드는 대부분 비동기적 코드이다.
콜백 함수를 익명 함수로 전달하는 과정이 반복되어 코드의 들여쓰기 수준이 감당하기 힘들 정도로 깊어지는 현상으로, 주로 이벤트 처리나 서버 통신과 같이 비동기적인 작업을 수행할 때 생길 수 있는 형태로, 가독성 저하나 코드 수정이 어려워진다는 문제가 있다.
// 0.5초 주기마다 커피목록을 수집하고 출력
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 coffelist = '';
var addEspresso = function(name) {
coffeList = name;
console.log(coffeList);
setTimeout(addAmericano, 500, '아메리카노');
};
var addAmericano = function(name) {
coffeList = name;
console.log(coffeList);
};
setTimeout(addEspresso, 500, '에스프레소');
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('카페라떼'))
var addCoffee = function (prevName, name) {
setTimeout(function () {
coffeeMaker.next(prevName ? prevName + ', ' + name : name)
}, 500)
}
var coffeeGenerator = function* () {
var americano = yield addCoffee('', '아메리카노')
console.log(americano)
var mocha = yield addCoffee('', '카페모카')
console.log(mocha)
var latte = yield addCoffee('', '카페라떼')
console.log(latte)
var espresso = yield addCoffee('', '에스프레소')
console.log(espresso)
}
var coffeeMaker = coffeeGenerator()
coffeeMaker.next()
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()
『코어 자바스크립트』 (정재남, 위키북스)