콜백패턴

함수는 객체다. 즉 함수를 다른 함수의 인자로 전달할 수 있다.
introduceBugs()함수를 writeCode() 함수의 인자로 전달하면, 이때 introduceBugs()를 콜백함수 또는 간단하게 콜백이라고 부른다.
즉 함수를 다른 함수의 인자로 전달하면, 인자로 전달된 함수를 콜백함수라고 한다.

function writeCode(callback) {
    // 어떤 작업을 한다.
    callback();
    // ...
}

function introduceBugs() {
    // 버그를 만든다.
}
writeCode(introduceBugs);

introduceBugs()가 writeCode()의 인자로 괄호 없이 전달된 사실을 눈여겨 봐야한다.
괄호를 붙이면 함수가 실행되는데 이 경우는 함수의 참조만 전달하고 있다.

콜백예제를 설명하기 위해 긴 예제가 사용된다. 한번 사용하고 리팩토링해서 다시 사용한다.

findNodes 함수는 DOM 노드의 배열을 반환한다. hide() 함수는 노드를 숨긴다.

var findNodes = function () {
    var i = 100000, // 긴루프
        nodes = [], // 결과를 저장할 배열
        found; // 노드 탐색 결과
    while (i) {
        i -= 1;
        // 이 부분에 복잡한 로직이 들어간다
        nodes.push(found);
    }
    return nodes;
};

var hide = function (nodes) {
    var i = 0, max = nodes.length;
    for (; i < max; i += 1) {
        nodes[i].style.desplay = 'none';
    }
};

// 함수실행
hide(findNodes());

아래의 에제는 fineNodes()에서 반환된 노드의 배열에 대해 hide()가 다시 루프를 돌아야하기 때문에 비효율적이다. findNodes()에서 노드를 선택하고 바로 숨긴다면 재차 루프를 돌지 않아 더 효율적일 것이다.
그렇지만 findNodes()안에서 노드를 숨기는 로직을 구현하면 탐색과 수정 로직의 결합으로 인해 범유 함수의 의미가 퇴색될 것이다.
이때 바로 콜백 패턴을 사용한다. 노드를 숨기는 로직의 실행을 콜백 함수에 위임하고 이 함수를 findNodes()에 전달한다.

아래는 수정된 코드

// findNodes() 가 콜백을받도록 리팩터링한다.
var findNodes = function (callback) {
    var i = 100000,
        nodes = [],
        found;

    // 콜백 함수를 호출할 수 있는지 확인한다.
    if (typeof callback !== 'function') {
        callback = false;
    }

    while (i) {
        i -=1;
        // 이곳에 복잡한 로직을 구현한다.

        // 여기서 콜백을 실행한다.
        if (callback) {
            callback(found);
        }

        nodes.push(found);
    }
    return nodes;
};

var hide = function (node) {
    node.style.display = 'none';
}

// 노드를 찾아서 바로 숨긴다.
findNodes(hide);

이 방법은 직관적이다. findNodes()에는 콜백함수가 추가되었는지 확인하고, 있으면 실행하는 작업 하나만 추가되었다.
콜백은 생략할 수 있기 때문에 리팩터링된 findNodes()는 여전히 이전과 동일하게 사용할 수 있고, 기존 API에 의존하는 코드를 망가뜨리지 않는다.

출처 : JavaScript Patterns