콜백함수는 다른함수에 의해 호출되는 함수이다.
기본적으로 함수의 파라미터에 함수가 들어가있는 구조인데,
자바스크립트 비동기처리의 시작이라고 할 수 있다.
예시로 setTimeout 함수를 보자.
setTimeout(func(),2000)
를 실행하면 2초뒤에 콜백함수인 func가 실행된다.
( ※ task queue가 비어있을 경우지만)
Callback은 ES6에서 Promise가 표준화되기 전까지 공식적 비동기처리 방법이었고,
ES6 문법에서 또한 매우 자주 쓰인다.
그렇다면 콜백은 어떻게, 왜 사용하는걸까?
이 궁금증을 해결하려면, 먼저 동기와 비동기의 개념을 이해해야한다.
javascript는 기본적으로 동기방식이기 때문에 당연히 순서대로 출력될 것이다. 그런데 생각해보자. 만약 세탁하는데 30분이 걸린다면?
세탁이 끝날때까지 30분을 기다리고, 빨래를 뺀 뒤, 청소와 설거지를 해야한다.
세탁기가 돌아가는동안 다른걸 할수가 없으니 비효율적이다.
반면 위와 같이 비동기 방식으로 짜면 출력은 다음과 같다.
1. "세탁기에 빨래 넣기" 출력
2. "방청소 하기" 출력
3. "설거지 하기" 출력
4. 30분 뒤, "빨래 빼기" 출력
setTimeout()을 실행한뒤 바로 다음 코드를 실행하기 때문이다.
이렇게되면 빨래가 돌아가는동안 방청소와 설거지를 할 수 있다!
왜 비동기방식으로 프로그래밍을 하는지 대충 감이 올 것이다.
javascript는 single thread 환경이다. 웹 환경이라고 가정했을때,
동기방식을 사용할 경우 한가지 request가 들어오면 처리가 끝날때까지 다른 request를 받지 못하는 것이다. 위의 세탁기 예시 처럼 말이다.
때문에 효율적으로 여러 작업을 처리할 수 있는 비동기 방식으로 프로그래밍한다.
그러면 콜백함수가 비동기 프로그램에서 어떻게 사용된다는걸까?
먼저 콜백함수를 사용하지않으면 어떻게 되는지 보자.
아래에 먹은 칼로리를 계산하는 비동기식 프로그램이 있다.
eat함수는 음식의 칼로리와 갯수를 파라미터로 받고, 1초간 먹은뒤,
먹은 칼로리의합 (칼로리 X 갯수)을 리턴한다.
printWeight은 단순 출력함수다.
위처럼 300kcal 음식 5개를 먹었다면, 1500kcal가 출력되어야한다.
하지만 해괴망측한 결과가 나왔다... 그 이유는
setTimeout은 비동기API 이므로 호출된 후 바로 다음 Line인 printWeight을 실행했고, total에 값이 들어오기 전에 kcal를 출력해버렸기 때문이다.
다시 올바르게 작성해보자.
위와 같이 작성하면,
원하는 결과가 나왔다. printWeight을 eat함수의 파라미터로 넘겨 데이터가 들어온 후 호출되도록 했기 때문이다. 이처럼 원하는 시점에서의 호출을 위해 즉,
javascript의 올바른 비동기처리를 위해 콜백함수를 사용한다.
콜백함수를 인자로 갖는 함수는 작성하는 법은 간단하다.
함수를 정의할 때, 함수타입 파라미터를 하나 더 넣어주고 원할때 호출하면 된다.
const myfunc=(name,callback)=>{
console.log("My name is",name)
callback(); //console.log 후 callback() 실행
}
콜백함수의 제어권은 인자로 들어간 함수에 위임된다.
위의 경우, callback()의 제어권은 myfunc에게 있다.
따라서 myfunc내부 로직에따라(위의 경우는 console.log 이후) 적절히 callback함수가 실행될 것이다.
이름부터 무섭다!
아래처럼 콜백함수를 남발하게되면 콜백지옥에 빠질수있다.
step1(function (value1) {
step2(function (value2) {
step3(function (value3) {
step4(function (value4) {
step5(function (value5) {
step6(function (value6) {
// Do something with value6
});
});
});
});
});
});
콜백함수가 깊어지면 가독성과 유지/보수 효율이 떨어진다.
만약 협업에서 누군가 이렇게 적은 코드를 수정해야한다면 몹시 화날것이다...
그리고 이를 해결하기위해 나온것이 Promise와 async / await 이다.