콜백(Callback) 함수
콜백 함수는 전달인자로 다른 함수에 전달되는 함수를 말한다.
'use strict'
function print(callback) {
callback();
}
/**
* print 함수의 매개변수에 함수를 전달
*/
print(
function () {
console.log('callback!');
}
);
// callback!
위 예시처럼 printCallback이라는 함수의 인자 값으로 callback이라는 함수 파라미터를 받아서 함수 내부에서 호출을 하고 있다. 자바스크립트에서는 위 예시와 같이 함수의 파라미터로 전달되는 다른 함수를 콜백 함수라고 한다.
콜백함수는 주로 비동기 작업이나 이벤트 처리 시 동기화를 위해서 사용되고, 특정 작업이 완료된 후 실행시킬 코드를 정의하는데 사용된다.
콜백함수(callback function)의 사용
1. setTimeout과 같은 타이머 처리에 사용
function greeting(name) {
console.log('Hello, ' + name);
}
/**
* 3초뒤 callback 함수인 greeting이 실행
* */
setTimeout(function() {
greeting('bill');
},3000);
2. Array Method (map, filter, forEach)과 같은 타이머 처리에 사용
let numbers = [1,2,3,4,5,6];
/**
* 1. forEach 구문에 callback 적용
* */
numbers.forEach(function(number) {
console.log(number*2); // [2,4,6,8,10,12]
});
/**
* 2. map 구문에 callback 적용
* */
let exMap = numbers.map(function(number) {
return number * 2;
});
console.log(exMap);// [2,4,6,8,10,12]
/**
* 3. filter 구문에 callback 적용
* */
let exFilter = numbers.filter(function(number) {
return number % 2 === 0;
});
console.log(exFilter); // [2,4,6]
3. EventListeners
addEventListener와 같은 DOM API에서도 매개인자값으로 콜백 함수를 사용할 수 있다.
document.querySelector('.mButton').addEventListener('click', function() {
console.log('btn click listeners'); // 콜백
})
4. 비동기(Asynchronous) 방식
외부에서 HTTP Request를 해서 값을 받아오는 비동기 통신에서도 콜백함수가 적용한다. 이때, 작업이 완료되었을 때 실행시킬 코드를 정의하는 역할을 한다.
fetch('Endpoint/api')
.then(function(response) { // 콜백
return response.json();
})
.then((data) => console.log('get data ->',data)) // 콜백
.catch((error) => console.error('error ->', error)); // 콜백
콜백함수(callback function) 사용법
콜백함수는 기본적인 일반 함수의 형식으로 사용할 수 있으나, 이밖에 다른 형식으로 사용할 수 있다. 각 방식은 크게 3가지로 기본적인 명명된 함수, 익명 함수, 화살표 함수와 같은 방식으로 만들 수 있다.
1. 명명된 함수
명명된 함수는 말 그대로 네이밍이 적용된 일반 함수 선언을 뜻 한다. 일반적으로 명명된 함수를 사용해서 콜백 함수에 적용하면 재사용성이 높아지고 가독성이 올라간다.
/**
* 명명된 callback 함수
* */
function plusHandler(number) {
return number + 1;
}
function minusHandler(number) {
return number - 1;
}
let numbers = [1, 2, 3, 4, 5];
let incrementedNumbers = numbers.map(plusHandler);
console.log(incrementedNumbers); // [2, 3, 4, 5, 6]
let decrementedNumbers = numbers.map(minusHandler);
console.log(decrementedNumbers); // [0, 1, 2, 3, 4]
2.익명 함수 사용
익명 함수는 함수에 이름이 없는 함수로, 자주 사용되는 형태이다. 매개변수에 함수를 전달하면 함수 네이밍을 굳이 명시할 필요가 없기 때문에, 단일 역할을 하는 콜백을 작성할 때, 보통 익명 함수 형태로 많이 많이 사용한다.
let incrementedNumbers = numbers.map(function(number) { // 함수명이 존재하지 않는 콜백으로 익명함수를 적용
return number + 1;
});
console.log(incrementedNumbers);
3. 화살표 함수(arrow function) 사용
일반적인 function 형식으로 콜백을 구성할 수 있지만, 이를 생략한 화살표 함수로도 콜백을 구성할 수 있다. 화살표 함수를 사용하면 콜백함수를 작성할 때, 보다 더 간결하게 적용할 수 있다.
// 매개변수가 1개일 경우 기본 function 키워드로 작성하는것 보다 더 간결하게 작성가능하다.
let incrementedNumbers = numbers.map((number) => number + 1);
console.log(incrementedNumbers);
콜백 사용시 주의점
Callback this
자바스크립트에서 this 키워드는 함수가 호출되는 방법에 따라서 달라진다. 콜백 함수 내에서 this가 예상한 객체를 참조하는 않는 경우가 발생할 때가 있는데, 이는 함수가 호출되는 실행 컨텍스트 때문에 발생한다. 콜백 함수가 다른 객체의 메서드로 전달되거나, 비동기를 처리할 때 this를 가져오지 못해서 문제가 발생할 수 있다. 아래는 콜백 함수에서 this를 찾지 못하는 예시이다.
const obj = {
value: 'bill',
method: function() {
console.log(this.value); // bill
setTimeout(function() {
// undefined, 콜백에서 this는 전역 객체를 참조, 전역 this는 undefined 이기 때문에 undefined 출력
console.log(`callback ${this.value}`);
}, 1000);
}
};
obj.method();
// bill
// undefined
위 예시에서 obj 내부 setTimeout의 콜백 함수 내에 console.log(this.value); 는 obj의 this가 아닌 전역 window의 전역 객체를 참조한다. 그렇기 때문에 예상한 bill, callback bill 출력되지 않고 bill, undefined를 출력한다.
해결
위와 같은 경우에서 화살표 함수(arrow function)를 사용하면 콜백함수가 전역 스코프가 아닌 상위 스코프인 obj this를 사용하기 때문에 원하는 bill, callback bill을 출력할 수 있다.
자바스크립트에서 호출 컨텍스트가 변경될 때, 기본 함수 형태인 function 키워드를 사용하면 전역 객체(window)를 참조할 수 있으나, 화살표 함수를 사용하면 this 바인딩을 가지지 않고, 바로 상위 스코프의 this를 참조하기 때문에 전역 객체를 참조하지 않는다.
const obj = {
value: 'bill',
method: function() {
console.log(this.value); // bill
setTimeout(() => {
console.log(`callback ${this.value}`);
}, 1000);
}
};
obj.method();
// bill
// callback bill
Callback Hell
콜백 헬은 중첩된 콜백 함수로 인해서 코드가 복잡해지고 가독성이 떨어지는 현상을 말한다. 매개변수로 넘어가는 콜백 함수가 반복돼서 코드의 Depth가 매우 깊어지기 때문에 디버깅이나 코드 파악이 매우 어렵다. 아래와 같이 콜백헬이 발생했을 때, Promise나 async/await방식을 통해서 해결할 수 있다.
// callback hell
doSomething(function(result1) {
doSomethingElse(result1, function(result2) {
doAnotherThing(result2, function(result3) {
doFourthThing(result3, function(result4) {
doFifthThing(result4, function(result5) {
doSixthThing(result5, function(result6) {
doSeventhThing(result6, function(result7) {
doEighthThing(result7, function(result8) {
doNinthThing(result8, function(result9) {
doTenthThing(result9, function(result10) {
console.log('Final callback hell result:', result10);
});
});
});
});
});
});
});
});
});
});
참고자료
'Language > JS & TS' 카테고리의 다른 글
[JS] 가비지 컬렉션(Garbage Collection) (0) | 2024.05.01 |
---|