비동기 함수란 쉽게 설명하면 호출부에서 실행 결과를 가다리지 않아도 되는 함수이고, 반대로 동기 함수는 호출부에서 실행 결과가 리턴될 때 까지 기다려야 하는 함수다.
때문에 자바스크립트처럼 싱글 쓰레드 환경에서 실행되는 언어에서 광범위하게 사용 되고 많은 시간이 할애되는 로직을 처리하는데 오랜 시간 동안 대기 해야하는 불상사를 막을 수 있다.
하지만 비동기식 처리 모델은 순서 보장이 되지 않는다는 단점이 하나 있는데,
콜백함수를 알기 위해선 아래의 개념들을 정리할 필요가 있다
함수의 매개변수로 전달이 가능
함수의 반환 값(return)으로 사용 가능
할당 및 동일 비교도 가능함
위의 설명과 같이, 함수는 변수에 저장할 수 있다.
그리고 함수는, 함수를 담은 변수를 전달인자로 받을 수 있다
마찬가지로 함수 내부에서 변수에 함수를 할당할 수 있고 함수는 이 변수를 리턴할 수 있다
여기서 변수에 할당하지 않고 함수를 바로 이용할 수 있는데, 어떤 *고차 함수에 함수를 전달인자로 전달하고, 고차 함수는 함수 자체를 리턴하는 방법이 바로 그것이다
변수가 빠졌을 뿐, 동일하게 동작한다
이때 다른 함수(caller)의 전달인자(argument)로 전달되는 함수를 콜백 함수(callback function)라고 한다.
어떤 작업이 완료되었을 때 호출하는 경우가 많아서, 답신 전화를 뜻하는 콜백 함수라는 이름이 붙여졌다.
*고차함수
인자로 함수를 받거나 ( = 콜백함수 )
함수를 반환하는 함수
다른 함수를 인자로 받는 경우
function double(num) {
return num * 2;
}
function doubleNum(func, num) {
return func(num);
}
/*
* 함수 doubleNum은 다른 함수를 인자로 받는 고차 함수입니다.
* 함수 doubleNum의 첫 번째 인자 func에 함수가 들어올 경우
* 함수 func는 함수 doubleNum의 콜백 함수입니다.
* 아래와 같은 경우, 함수 double은 함수 doubleNum의 콜백 함수입니다.
*/
let output = doubleNum(double, 4);
console.log(output); // -> 8
함수를 리턴하는 경우
function adder(added) {
return function (num) {
return num + added;
};
}
/*
* 함수 adder는 다른 함수를 리턴하는 고차 함수입니다.
* adder는 인자 한 개를 입력받아서 함수(익명 함수)를 리턴합니다.
* 리턴되는 익명 함수는 인자 한 개를 받아서 added와 더한 값을 리턴합니다.
*/
// adder(5)는 함수이므로 함수 호출 연산자 '()'를 사용할 수 있습니다.
let output = adder(5)(3); // -> 8
console.log(output); // -> 8
// adder가 리턴하는 함수를 변수에 저장할 수 있습니다.
// javascript에서 함수는 일급 객체이기 때문입니다.
const add3 = adder(3);
output = add3(2);
console.log(output); // -> 5
함수를 인자로 받고, 함수를 리턴하는 경우
function double(num) {
return num * 2;
}
function doubleAdder(added, func) {
const doubled = func(added);
return function (num) {
return num + doubled;
};
}
/*
* 함수 doubleAdder는 고차 함수입니다.
* 함수 doubleAdder의 인자 func는 함수 doubleAdder의 콜백 함수입니다.
* 함수 double은 함수 doubleAdder의 콜백으로 전달되었습니다.
*/
// doubleAdder(5, double)는 함수이므로 함수 호출 기호 '()'를 사용할 수 있습니다.
doubleAdder(5, double)(3); // -> 13
// doubleAdder가 리턴하는 함수를 변수에 저장할 수 있습니다. (일급 객체)
const addTwice3 = doubleAdder(3, double);
addTwice3(2); // --> 8
즉, 정리하자면 콜백함수는 파라미터로 전달받은 함수
파라미터로 콜백함수를 전달받고 함수 내부에서 필요할 때 콜백함수를 호출할 수 있다.
const printString = (string, callback) => {
setTimeout (
() => {
console.log(string)
callback()
},
Math.floor(Math.random() * 100) + 1
)
}
const printAll = () => {
printString("A", () => {
printString("B", () => {
printString("C", () => {})
})
})
}
printAll() // ABC
const printAll 은 printString을 실행하는데, 처음엔 A와 콜백을 받아서 넘긴다
그러면 setTimeout의 콜백에서 A단계에서 넘겨진 콜백이 실행된다
마찬가지로 B와 또 콜백을 받아서 넘기게 되어 setTimeout을 거치게 되고
마지막엔 C와 콜백을 받아 넘겨서 또 똑같은 루트대로 실행이 된다