자바스크립트 비동기 처리에 사용되는 객체
특정 코드의 연산이 끝날 때까지 코드의 실행을 멈추지 않고, 다음 코드를 먼저 실행하는 자바스크립트의 특성
function getData() {
var tableData;
$.get('https://domain.com/products/1', function(response) {
tableData = response;
});
return tableData;
}
console.log(getData()); // undefined
자바스크립트에서 비동기 처리가 필요한 이유는 화면에서 서버로 데이터를 요청했을 때 서버가 언제 그 요청에 대한 응답을 줄지도 모르는데 마냥 다른 코드를 실행 안 하고 기다릴 수 없기 때문이다.
간단한 요청 1개를 보냈는데, 만약 100개를 받는다고 생각해보면, 비동기 처리가 아니고 동기 처리일 때, 코드를 실행하고, 기다리고, 실행하고, 기다리고를 반복하게 되어 웹 애플리케이션을 실행하는데 수십 분은 걸릴 것이다.
// #1
console.log('Hello');
// #2
setTimeout(function() {
console.log('Bye');
}, 3000);
// #3
console.log('Hello Again');
비동기 처리에 대한 이해가 없는 상태라면 위 코드를 볼 때, 다음과 같은 결과값이 나올 거라고 생각할 수 있다.
그런데 실제 결과 값은 아래와 같이 나온다
setTimeout()
역시 비동기 방식으로 실행되기 때문에 3초를 기다렸다가 다음 코드를 수행하는 것이 아니라, 일단 setTimeout()을 실행하고 나서 바로 다음 코드인 console.log('Hello Again');
으로 넘어갔다. 따라서, 'Hello', 'Hello Again'을 먼저 출력하고 3초가 지나면 'Bye'가 출력된다.
비동기 처리 방식이 생기는 문제들을 해결하려면 콜백(callback) 함수를 이용해야 한다. 앞에서 살펴본 ajax 통신 코드를 콜백 함수로 개선하면 다음과 같다.
function getData(callbackFunc) {
$.get('https://domain.com/products/1', function(response) {
callbackFunc(response); // 서버에서 받은 데이터 response를 callbackFunc() 함수에 넘겨준다.
});
}
getData(function(tableData) {
console.log(tableData); // $.get()의 response 값이 tableData에 전달됨
});
이렇게 콜백 함수를 사용하면 특정 로직이 끝났을 때 원하는 동작을 실행시킬 수 있다.
콜백 함수의 동작 방식은 일종의 식당 자리 예약과 비슷하다. 일반적으로 맛집에는 사람이 많아서 자리가 없다. 그래서 대기자 명단에 이름을 쓴 다음에 자리가 날 때까지 주변 식당을 돌아다닌다. 만약 식당에서 자리가 생기면 전화로 자리가 났다고 연락이 온다. 그 전화를 받는 시점이 여기에서 콜백 함수가 호출되는 시점과 같다. 손님 입장에서는 자리가 날 때까지 식당에서 기다리지 않고, 근처에서 잠깐 쇼핑을 할 수도 있고 아니면 다른 식당 자리를 알아볼 수도 있다.
자리가 났을 때만 연락이 오기 때문에 미리 가서 기다릴 필요도 없고, 직접 식당 안에 들어가서 자리가 비어 있는지 확인할 필요도 없다. 자리가 준비된 시점, 즉 데이터가 준비된 시점에서만 우리가 원하는 동작(자리에 앉는다, 특정 값을 출력한다 등)을 수행할 수 있다.
콜백 지옥은 비동기 처리 로직을 위해 콜백 함수를 연속해서 사용할 때 발생하는 문제이다.
$.get('url', function(response) {
parseValue(response, function(id) {
auth(id, function(result) {
display(result, function(text) {
console.log(text);
});
});
});
});
웹 서비스를 개발하다 보면 서버에서 데이터를 받아와 화면에 표시하기까지 인코딩, 사용자 인증 등을 처리해야 하는 경우가 있다. 만약 이 모든 과정을 비동기로 처리해야 한다고 하면 위와 같이 콜백 안에 콜백을 계속 무는 형식으로 코딩을 하게 된다. 이러한 코드 가독성도 떨어지고 로직을 변경하기도 어렵다. 이와 같은 코드 구조를 콜백 지옥이라고 한다.
일반적으로 콜백 지옥을 해결하는 방법에는 Promise
나 Async
를 사용하는 방법이 있다. 만약 코딩 패턴으로만 콜백 지옥을 해결하려면 아래와 같이 각 콜백 함수를 분리해주면 된다.
function parseValueDone(id) {
auth(id, authDone);
}
function authDone(result) {
display(result, displayDon)
}
function displayDone(text) {
console.log(text);
}
$.get('url', function(response) {
parseValue(response, parseValueDone);
});
위 코드는 위의 콜백 지옥 예시를 개선한 코드이다. 중첩해서 선언했던 콜백 익명 함수를 각각의 함수로 구분하였다. 정리된 코드를 간단하게 살펴보면, 먼저 ajax 통신으로 받은 데이터를 parseValue() 메서드로 파싱한다. parseValueDone()에 파싱 한 결과값인 id가 전달되고 auth() 메서드가 실행된다. auth() 메서드로 인증을 거치고 나면 콜백 함수 authDone()이 실행된다. 인증 결과 값인 result로 display()를 호출하면 마지막으로 displayDone() 메서드가 수행되면서 text가 콘솔에 출력된다.
위와 같은 코딩 패턴으로도 콜백 지옥을 해결할 수 있지만 Promise나 Async를 이용하면 더 편하게 구현할 수 있다.