시대의 명작 코어 자바스크립트를 읽고 자바스크립트 마스터에 도전합니다...
코어 자바스크립트(web) : 콜백
콜백 함수(callback function)는 다른 코드(함수 또는 메서드)의 인자로 넘겨주는 함수이다. 함수 실행에 대한 제어권도 함께 위임한다. 위임받은 코드는 자체적인 로직에 의해 이 콜백 함수를 적절한 시점에 실행한다.
1) 콜백 함수의 제어권을 넘겨받은 코드는 콜백 함수 호출 시점에 대한 제어권을 가진다.
var count = 0;
var cbFunc = function () {
console.log(count);
if (++count > 4) clearInterval(timer);
};
var timer = setInterval(cbFunc, 300);
2) 콜백 함수의 제어권을 넘겨받은 코드는 콜백 함수를 호출할 때 인자에 어떤 값들을 어떤 순서로 넘길 것인지에 대한 제어권을 가진다.
Array.prototype.map(callback[, thisArg])
callback: function(currentValue, index, array)
3) 콜백 함수의 this가 무엇을 바라보게 할지 정해진 경우도 있다. 정하지 않은 경우에는 전역객체를 바라본다. 사용자가 임의로 this를 바꾸고 싶은 경우 bind 메서드를 사용한다.
Array.prototype.map = function (callback, thisArg) {
var mappedArr = [];
for (var i = 0; i < this.length; i++) {
var mappedValue = callback.call(thisArg || window, this[i], i, this);
mapperArr[i] = mappedValue;
}
return mappedArr;
}
제어권을 넘겨받을 코드에서 call/apply 메서드의 첫 번째 인자에 콜백함수 내부에서의 this가 될 대상을 명시적으로 바인딩한다.
어떤 함수의 인자에 객체의 메서드를 전달하더라도 이는 결국 메서드가 아닌 함수일 뿐이다! 콜백이 함수로서 호출되면 함수 내부의 this는 전역객체를 바라본다.
var obj = {
vals: [1, 2, 3],
logValues: function(v, i) {
console.log(this, v, i);
}
};
obj.logValues(1, 2); // { vals: [1, 2, 3], logValues: f } 1 2
[4, 5, 6].forEach(obj.logValues); // Window { ... } 4 0
// Window { ... } 5 1
// Window { ... } 6 2
var self = this
var obj1 = {
name: 'obj1',
func: function () {
var self = this;
return function () {
console.log(self.name);
};
}
};
var callback = obj1.func();
setTimeout(callback, 1000);
...
var obj2 = {
name: 'obj2',
func: obj1.func
};
var callback2 = obj2.func();
setTimeout(callback2, 1500);
var obj3 = { name: 'obj3' };
var callback3 = obj1.func.call(obj3);
setTimeout(callback3, 2000);
this
를 사용하지 않은 경우(재활용 불가!)var obj1 = {
name: 'obj1',
func: function () {
return function () {
console.log(obj1.name);
};
}
};
setTimeout(obj1.func, 1000);
var obj1 = {
name: 'obj1',
func: function () {
console.log(this.name);
}
};
setTimeout(obj1.func.bind(obj1), 1000);
var obj2 = { name: 'obj2' };
setTimeout(obj1.func.bind(obj2), 1500);
콜백 지옥이란 콜백 함수를 익명으로 전달하는 과정이 반복되어 코드의 들여쓰기 수준이 감당하기 힘들어질 정도로 깊어지는 현상이다. 보통은 이벤트 처리나 비동기적인 작업을 수행하기 위해 이런 형태가 자주 등장한다.
1. 기명 함수로 변환 : 코드 가독성을 높일 수 있다.
2. Promise : new 연산자와 함께 호출한 Promise의 인자로 넘겨주는 콜백 함수는 호출할 때 바로 실행되지만 내부에 resolve 또는 reject 함수를 호출하는 구문이 있을 경우 둘 중 하나가 실행되기 전까지는 then 또는 catch로 넘어가지 않는다.
3. Generator : next 메서드를 호출하면 Generator 함수 내부에서 가장 먼저 등장하는 yield에서 함수의 실행을 멈춘다. 비동기 작업이 완료되는 시점마다 next를 호출하면 내부의 소스를 위에서 아래로 순차적으로 할 수 있다.
4. async/await : 비동기 작업을 수행하고자 하는 함수 앞에 async를 표기하고 함수 내부에서 실질적인 비동기 작업이 필요한 위치마다 await를 표기하는 것 만으로도 뒤의 내용을 Promise로 자동 전환하고 해당 내용이 resolve된 이후에 다음으로 넘어간다.