본문 바로가기
Develop/백엔드 & 서버

Javascript는 비동기를 어떻게 처리해 - 콜백함수

by 구운밤이다 2021. 1. 20.
728x90
반응형

시리즈 목차

이 글은 시리즈 글입니다. 이번 글에서는 자바스크립트에서 처음으로 비동기 작업을 다뤘던 방식인 콜백함수에 대해 알아볼 것입니다. 기본적으로 자바스크립트가 비동기로 동작하지 않는다는 사실은 저번 글에서 다루었죠! 자바스크립트가 비동기함수를 어떻게 처리하는지 동작 원리를 모르시는 분들은 이전 글을 참고해보세요!

콜백함수 예제

자바스크립트를 비동기 처리하기 위해 제일 처음으로 등장했던 방식은 콜백함수를 이용해 처리하는 것이었습니다. 요즘은 이 방식을 잘 사용하지 않지만요. 이전 글에서도 setTimeout함수가 콜스택에 들어가면 webapi에 타이머를 설정해두고 콜백함수를 콜백큐에 전달했었죠. 그때 등장했던 콜백 함수는 콜백큐에서 콜스택이 비길 기다렸다가 콜스택이 비었을 때 콜스택으로 이동하고 실행 후 제거됩니다.

그렇다면 콜백함수는 뭘까요. 콜백은 직역하면 전화를 다시 하는 것이죠. 뭔가 내가 할 일을 다른 객체에게 시키고 나는 다른 일을 하고 있을테니 다 끝나면 그때 처리하겠다는 것입니다. 정리하면 자바스크립트에서는 비동기 함수를 다른 객체에게 맡기고 작업 후에 부를 때까지 다른 일을 하고 있다가, 객체가 결과를 가지고 부르면 콜백함수를 통해 결과를 알맞게 처리해주는 것입니다.

예제

function getData(callbackFunc) {
    $.get('https://shop.com/products/1', function(response) {
        // 서버에서 받은 데이터 response를 callbackFunc() 함수에 넘겨줌
        callbackFunc(response); 
    });
}

getData(function(res) {
    console.log(res); // $.get()의 response 값이 res에 전달됨
});

이번엔 위의 ajax 예제를 한번 봅시다. 위 예제에서 getData를 정의할 때 response를 받아 콜백 함수로 전달해주죠. 그 아래에 getData를 실행하면서 콜백함수를 정의하고 get 요청의 응답을 res로 받아와 콘솔에 로그가 남게 됩니다.

틀린 예제

function getData() {
    let res;
    $.get('https://domain.com/products/1', function(response) {
        res = response;
    });
    return res;
}

console.log(getData()); // undefined

만약 위 예제를 비동기 콜백함수를 이용하지 않고 위와 같이 작성했다고 하면 콘솔에는 undefined가 나오게 됩니다. http 요청은 오래걸리므로 자바스크립트 런타임 환경인 브라우저에서 알아서 webapi에 넣고 비동기적으로 응답을 받고 아래 코드를 실행하게 되는데 이때 위 코드에서는 응답을 기다려 받지 않고 바로 리턴해버리기 때문에 값이 들어가지 않고 undefined가 로그에 남게 됩니다. 이렇게 논블로킹으로 진행하지 않고 하나하나 기다리면서 코드를 실행하면 웹 페이지 하나를 띄우는 것만 해도 족히 1분은 넘게 걸릴 것입니다.

문제점 콜백 지옥

예제 - 콜백 지옥

$.get('url', function(response) {
    parseRes(response, function(id) {
        saveAuth(id, function(result) {
            display(result, function(text) {
                console.log(text);
            });
        });
    });
});

하지만 요즘은 이렇게 콜백함수를 이용하는 방식을 잘 사용하지 않습니다. 위 예제를 보시죠. 맨 처음 예제처럼 콜백 함수들을 다중으로 겹쳐 작성한 모습입니다. Get 요청의 콜백으로는 이름 붙이지 않은 function이 있고 그 응답을 parseRes 에 전달하고, 두 번째 인자에 또 콜백 함수가 존재합니다. 이 콜백 함수 안에는 또 parseRes 함수의 결과값인 id를 받아 saveAuth 에 넘겨주고 saveAuth에서는 결과를 display에 넘겨주는 방식입니다. 위 설명만 보아도 복잡하죠? 여기서 조금만 더 복잡한 로직을 구현하려고 하면 상황은 더 안 좋아질 것입니다. 코드 또한 가운데가 쭉 나오는 이상한 형태이고 가독성도 좋지 않습니다. 이 형태를 콜백의 지옥에 빠진다고 해서 콜백 지옥, 콜백 헬 (callback hell) 이라고 합니다.

예제 - 개선

function parseResCallback(id) {
    saveAuth(id, saveAuthCallback);
}
function saveAuthCallback(res) {
    display(res, displayCallback);
}
function displayCallback(text) {
    console.log(text);
}
$.get('url', function(response) {
    parseRes(response, parseResCallback);
});

위를 코드를 분리하여 이런식으로 해결할 수 있습니다. Get 요청을 통해 받은 데이터를 parseRes() 메소드로 파싱하여 id를 parseResCallback 함수에 던져줍니다. 이 함수에서는 id를 saveAuth에 전달해주고 그 결과를 또 saveAuthCallback 함수에 전달해주는 형태이죠. saveAuthCallback에서는 전달받은 res를 display함수에 전달해 실행해줍니다. 마지막으로 display의 결과인 text를 displayCallback함수에 주고 이게 로그에 남게되죠. 이 형태도 이해하기 좋은 형태는 아닙니다.

이를 프로미스와 async await를 사용하면 더 읽기 좋게 해결할 수 있습니다. Promise 와 async await은 다음 글에서 알아보도록 할게요!


참고 - 자바스크립트 비동기 처리와 콜백 함수

728x90
반응형

댓글