콜백 함수 #5
Replies: 5 comments
-
콜백 지옥과 비동기 제어콜백 지옥은 콜백 함수를 익명 함수로 전달하는 과정이 반복되어 코드의 들여쓰기 수준이 감당하기 힘들정도로 깊어지는 현상입니다. 주로 이벤트 처리나 서버 통신과 같이 비동기작업을 수행하기 위해 이런 형태가 자주 등장하곤 합니다. 가독성이 떨어질뿐더러 코드를 수정하기도 어렵습니다. 비동기란?비동기는 동기의 반대말입니다. 동기적인 코드
비동기적인 코드
콜백 지옥(Callback Hell)콜백 지옥 예시 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,
'에스프레소'
); 단점
해결책 1 : 기명함수로 전환익명의 콜백 함수를 기명함수로 전환하였습니다. 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, '에스프레소'); 장점
단점
해결책 2 : PromiseES6에 도입된 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);
});
});
장점
단점
📌 Promise 복습시간 Promise를 사용할 때 알아야 할 핵심 개념은 바로 Promise의 상태입니다. new Promise()로 Promise를 생성하고 종료할 때까지 3가지의 상태를 가집니다.
Pending
new Promise() 이렇게 호출할 때 콜백 함수를 선언할 수 있고, 콜백 함수의 인자는 new Promise(function(resolve, reject){}) Fulfilled 콜백 함수의 인자 new Promise(function(resolve,reject){
resolve();
}) fulfilled 상태가 되면 then()을 이용하여 처리 결과 값을 받을 수 있습니다. function getData(){
return new Promise(function(resolve,reject){
var data = 100;
resolve(data);
})
}
getData().then(function(resolvedData){
console.log(resolvedData); // 100
}) Rejected 콜백 함수의 new Promise(function(resolve,reject){
reject();
})
function getData(){
return new Promise(function(resolve,reject){
reject(new Error("Request is failed!"));
});
}
getData().then().catch(function(error){
console.log(error); // Error: Request is failed!
}) 해결책 3 : GeneratorES6에 도입된 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();
장점
단점
📌 generator 복습시간 해결책 4 : Async/AwaitES2017에서 도입된 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));
console.log(coffeeList);
};
await _addCoffee('에스프레소');
await _addCoffee('아메리카노');
await _addCoffee('카페모카');
await _addCoffee('카페라떼');
};
coffeeMaker();
장점
단점
|
Beta Was this translation helpful? Give feedback.
-
4-2 제어권콜백 함수가 다른 요소에 의해 제어되는 경우를 대해 알아보자. 4-2-1 호출 시점콜백 함수의 제어권을 넘겨받은 코드는 콜백 함수 호출 시점에 대한 제어권을 가진다. 예를 들어 setIntervalvar intervalID = scope.setInterval(func, delay, 콜백 param1, 콜백 param2);
var count = 0;
var cbFunc = function () {
console.log(count);
if (++count > 4) clearInterval(timer);
};
var timer = setInterval(cbFunc, 300);
이와 같이 4-2-2 인자콜백 함수의 제어권을 넘겨받은 코드는 콜백 함수를 호출할 때 함수 인자에 어떤 값을 mapArray.prototype.map(callback, this로 인식할 배열)
callback: function(currentValue, index, map 메서드의 대상이 되는 배열) map의 콜백 함수
정상 작동아래 예시 실행 결과 newArr는 var newArr = [10, 20, 30].map(function (currentValue, index) {
console.log(currentValue, index);
return currentValue + 5;
});
console.log(newArr); //[15, 25, 35] 예상과 다른 작동하지만 인자의 순서를 임의로 바꾸는 경우 의도와 다른 값을 얻게 된다. 다음은 배열의 인자의 순서를 임의로 바꾸어 사용한 예시이다. 아래 예시 실행 결과 newArr는 var newArr = [10, 20, 30].map(function (index, currentValue) {
console.log(currentValue, index);
return currentValue + 5;
});
console.log(newArr); // [5, 6, 7]
4-2-3 this콜백 함수도 함수이기 때문에 기본적으로는 this가 전역객체를 참조하지만, 제어권을 넘겨받을 코드에서 콜백 함수에 별도로 this가 될 대상을 지정한 경우에는 그 대상을 참조하게 된다. (3-1-4절 참고) map 구현 예제
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);
mappedArr[i] = mappedValue;
}
return mappedArr;
}; 핵심은 var mappedValue = callback.call(thisArg || window, this[i], i, this);
이처럼 제어권을 넘겨받을 코드에서 콜백 함수 호출 방식에 따른 thissetTimeout(function () {
console.log(this); //Winodw
}, 300);
[1, 2, 3, 4, 5].forEach(function (x) {
console.log(this); //Window
});
document.body.innerHTML += '<button id="a">클릭</button>';
document.body.querySelector("#a").addEventListener("click", function (a) {
console.log(this, e); // (3) this는 <button id ="a">클릭</button> , e 는 MouseEvent {isTrusted: true, ...}
});
|
Beta Was this translation helpful? Give feedback.
-
콜백 함수 내부의
|
Beta Was this translation helpful? Give feedback.
-
4-1 콜백 함수란?콜백 함수는 제어권과 관련이 깊습니다. 콜백 함수는 다른 코드에게 인자로 넘겨줌으로써 그 제어권도 함께 위임한 함수입니다. 콜백 함수를 위임받은 코드는 자체적인 내부 로직에 의해 이 콜백 함수를 적절한 시점에 실행할 것입니다. 4-3 콜백 함수는 함수다콜백 함수로 어떤 객체의 메서드를 전달하더라도 그 메서드는 메서드가 아닌 함수로서 호출됩니다. var obj = {
vals: [1, 2, 3],
logValues: function(v, i) {
console.log(this, v, i);
}
}
obj.logValues(1, 2);
[4, 5, 6].forEach(obj.logValues); forEach에 의해 콜백이 함수로서 호출되고, 별도로 this를 지정하는 인자를 지정하지 않았으므로 함수 내부에서의 this는 전역 객체를 바라보게 됩니다. 결국 어떤 함수의 인자에 객체의 메서드를 전달하더라도 이는 결국 메서드가 아닌 함수일 뿐입니다. |
Beta Was this translation helpful? Give feedback.
-
콜백함수 사용 목적콜백함수 사용 목적에 대해 알아보자 예를 들어 어떤 일을 반복 수행하는 // n만큼 어떤 일을 반복한다.
function repeat1(n) {
// i를 출력한다.
for (var i = 0; i < n; i++) console.log(i);
}
repeat1(5); // 0 1 2 3 4
// n만큼 어떤 일을 반복한다.
function repeat2(n) {
for (var i = 0; i < n; i++) {
// i가 홀수일 때만 출력한다.
if (i % 2) console.log(i);
}
}
repeat2(5); // 1 3 두 함수 모두 같은 n번의 반복을 하고 있지만, 수행하는 로직이 다르다. 이렇게 함수의 일부분만이 다른데 매번 새로운 함수를 정의하는 것은 효율적이지 않다. 이를 함수의 합성, 즉 콜백함수를 이용한 추상화로 해결할 수 있다. 함수의 변하지 않는 공통 로직은 미리 정의해두고, 경우에 따라 변경되는 로직을 추상화해서 함수 외부에서 함수 내부로 전달하는 것이다. // 외부에서 전달받은 f를 n만큼 반복 호출한다.
// 수행하는 일을 함수 f로 추상화
function repeat(n, f) {
for (var i = 0; i < n; i++) {
f(i); // i를 전달하면서 f를 호출
}
}
var logAll = function (i) {
console.log(i);
};
// 반복 호출할 함수를 인수로 전달한다.
repeat(5, logAll); // 0 1 2 3 4
var logOdds = function (i) {
if (i % 2) console.log(i);
};
// 반복 호출할 함수를 인수로 전달한다.
repeat(5, logOdds); // 1 3
여기서, 함수의 매개변수를 통해 다른 함수의 내부로 전달되는 함수를 콜백 함수(callback function)이라고 하고, 매개변수를 통해 함수의 외부에서 콜백 함수를 전달받은 함수를 고차 함수(Higher-Order Function, HOF)라고 한다. 참고로, 매개변수를 통해 함수를 전달은 함수 뿐만 아니라, 반환값으로 함수를 반환하는 함수를 함수형 프로그래밍에서 고차 함수라 하며, 위 예시처럼 매개변수로 콜백함수를 받은 고차함수는 콜백함수를 자신의 일부분으로 합성한다. 고차 함수는 콜백 함수의 호출 시점을 결정해서 호출한다. 다시 말해, 콜백 함수는 고차함수에 의해 호출되며, 이때 고차 함수는 필요에 따라 콜백 함수에 인수를 전달할 수 있다. 단, 모든 콜백 함수가 고차 함수에 의해 호출되는 것은 아니다. 위 제어권에서 언급된 setTimeout, setInterval 과 같은 타이머 함수와 같은 경우에 사용되는 콜백 함수는 Web APIs인 타이머 함수에 의해 브라우저에 제어권을 넘기게 되며, 호출 주체는 브라우저가 되게 된다. 미세팁콜백 함수가 고차 함수 내부에만 호출된다면, 콜백 함수를 익명 함수 리터럴로 정의하여 고차 함수에 전달하는 것이 일반적이다. // 익명 함수 리터럴을 콜백 함수로 고차 함수에 전달한다.
// 익명 함수 리터럴은 repeat 함수를 호출할 때마다 평가되어 함수 객체를 생성한다.
repeat(5, function (i) {
if (i % 2) console.log(i);
}); // 1 3 이렇게 전달된 함수 리터럴은 고차 함수가 호출될 때마다 함수 객체를 생성하게 된다. 따라서 콜백 함수를 다른 곳에서도 호출할 필요가 있거나, 콜백 함수를 전달받는 함수가 자주 호출된다면, 함수 외부에서 콜백 함수를 정의한 후 함수 참조를 고차 함수에 전달하는 것이 효율적이다. // logOdds 함수는 단 한 번만 생성된다.
var logOdds = function (i) {
if (i % 2) console.log(i);
};
// 고차 함수에 함수 참조를 전달한다.
repeat(5, logOdds); // 1 3 참고: 모던 자바스크립트 Deep Dive, 이웅모 저 |
Beta Was this translation helpful? Give feedback.
-
이번주 주제는
콜백 함수
입니다. 아래 주제 중 1개를 선택하여 작성해주세요.주제1
주제 2
주제3
주제 4
주제5
Beta Was this translation helpful? Give feedback.
All reactions