Node.js에서 비동기 작업의 완료를 통지받는 가장 기본적인 메커니즘은 콜백이다. 콜백은 비동기 작업의 결과를 가지고 런타임에 호출되는 함수일 뿐이다.
콜백은 다른 모든 비동기 메커니즘을 기초로 하는 것들의 가장 기본적인 구성요소이다. 콜백 없이는 Promise가 존재할 수 없으면 따라서 async/await 또한 존재할 수 없다. 또한 스트림이나 이벤트 또한 불가능하다. 이것이 콜백이 어떻게 작동하는지 알아야 하는 이유이다.
콜백은 리액터 패턴의 핸들러를 구현한 것이다. Node.js에 독특한 프로그래밍 스타일을 제공하는 상징 중 하나이다.
콜백은 작업의 결과를 전달하기 위해서 호출되는 함수이며, 우리가 비동기 작업을 처리할 때 필요한 것이다. 비동기 세계에서 콜백은 동기적으로 사용되는 return 명령의 사용을 대신한다.
JavaScript는 콜백에 이상적인 언어인데 함수가 일급 클래스 객체(first class object)이면서 변수에 할당하거나 인자로 전달되거나 다른 함수 호출에서 반환되거나 자료구조에 저장될 수 있다. 콜백을 구현하는 또 다른 이상적인 구조는 **클로저(closure)**이다. 클로저를 사용하면 실제로 생성된 함수의 환경을 참조할 수 있다. 콜백이 언제 어디서 호출되는지에 관계없이 비동기 작업이 요청된 컨텍스트를 항상 유지할 수 있기 때문이다.
JavaScript에서 콜백은 다른 함수에 인자로 전달되는 함수이며, 작업이 완료되면 작업 결과를 가지고 호출된다. 함수형 프로그래밍에서 이런 식으로 결과를 전달하는 방식을 **연속 전달 방식(CPS: continuation-passing style)**이라고 한다. 이는 일반적인 개념이며, 항상 비동기 작업과 관련이 있는 것은 아니다. 단순히 결과를 호출자에게 직접 반환하는 대신 결과를 다른 함수(콜백)로 전달하는 것을 말한다.
function add(a, b) {
return a + b;
}
위 결과는 return 문을 통해 호출자에게 전달된다. 이것을 **직접 스타일(direct style)**이라고 하며, 동기식 프로그래밍에서 일반적으로 결과를 반환하는 방식을 보여준다.
//연속 전달 방식
function addCps(a, b, cb) {
cb(a + b);
}
console.log('before');
addCps(1, 2, rs => {
console.log(`Result : ${rs}`);
});
console.log('before');
위 함수는 동기 CPS함수로 콜백 또한 작업이 완료되었을 때 작업을 완료한다. 동기적이기 때문에 실행하면 순서대로 출력이 된다.
function additionAsync(a, b, cb) {
setTimeout(() => cb(a + b), 100);
}
console.log('before');
additionAsync(1, 2, rs => {
console.log(`Result : ${rs}`);
});
console.log('after');