자바스크립트의 비동기 처리란 특정 코드의 연산이 끝날 때까지 코드의 실행을 멈추지 않고 다음 코드를 먼저 실행하는 자바스크립트의 특성을 의미합니다.
예를들어, 웹 어플리케이션에서 서버 쪽 데이터가 필요할 때는 Ajax 기법을 사용하여 서버의 API를 호출함으로써 데이터를 수신합니다. 이렇게 서버의 API를 사용해야 할 때는 네트워크 송수신 과정에서 시간이 걸리기 때문에 작업이 즉시 처리되는 것이 아니라, 응답을 받을 때까지 기다렸다가 전달받은 응답데이터를 처리합니다. 이 과정에서 해당 작업을 비동기적으로 처리하게 됩니다.
제이쿼리의 ajax입니다.
function fetchData() {
let result;
$.get('https://jsonplaceholder.typicode.com/todos/1', function(response){
result = response;
})
return result;
}
console.log(fetchData()); // undefined
여기서 $.get()이 ajax 통신을 하는 부분입니다. 지정된 URL(https://jsonplaceholder.typicode.com/todos/1
)에 데이터 요청을 하고 받아온 데이터가 response에 담기고 result = response;
코드로 받아온 데이터를 result
에 저장합니다.
그럼 이제 fetchData()를 호출 하면 값이 나와야 하는데 undefined이 출력됩니다. 왜 그럴까요?
이유는 $.get()로 데이터를 요청하고 받아올 때까지 기다리지 않고 다음 코드인 return result;
를 실행했기 때문에 undefined이 출력됩니다.
이렇게 특정 로직의 실행이 끝날 때까지 기다려주지 않고 다음 코드를 실행하는 것이 비동기 처리입니다.
setTimeout()은 Web API의 한 종류입니다. 코드를 바로 실행하지 않고 지정한 시간만큼 기다렸다가 로직을 실행합니다
// #1
console.log('1');
// #2
setTimeout(function() {
console.log('2');
},3000)
// #3
console.log('3');
비동기 처리를 모르는 사람이 보면 위의 코드는 '1' -> 3초후 '2' -> '3' 순으로 출력된다고 생각할 수 있습니다.
하지만, 실제 결과값은 '1' -> '3' -> 3초 후 '2'가 출력됩니다.
setTimeout()는 비동기 방식으로 실행되기 때문에 3초를 기다렸다가 다음 코드를 수행하는 것이 아니라 일단 setTimeout()을 실행하고 나서 바로 다음 코드인 console.log(3);으로 넘어갔습니다. 따라서, '1', '3'을 먼저 출력하고 3초가 지나면 ‘2’가 출력됩니다.
위에서의 비동기 처리 방식으로 인한 문제들을 해결할 수 있는 방법은 바로 콜백함수를 사용하는 것입니다.
위의 비동기 처리 사례 1
의 코드를 콜백함수를 이용하여 수정해 보았습니다.
function fetchData(callback) {
$.get('https://jsonplaceholder.typicode.com/todos/1', function(response){
callback(response); // 서버에서 받아온 데이터(response)를 콜백함수에 넘겨줍니다.
});
}
fetchData(function(receivedData) { // $.get()의 response값이 receivedData에 전달됨
console.log(receivedData);
// Object {userId: 1, id: 1, title: "delectus aut autem", completed: false}
})
이렇게 콜백함수를 사용하면 특정 로직이 끝났을 때 원하는 동작을 실행시킬 수 있습니다.
1초에 걸쳐서 10, 20, 30, 40 과 같은 형태로 여러 번 순차적으로 처리하고 싶다면 콜백함수를 중첩해서 사용 할 수 있습니다.
function increase(number, callback) {
setTimeout(() => {
const result = number + 10;
if(callback) {
callback(result);
}
},1000)
}
console.log('시작!')
increase(0, first => {
console.log(first);
increase(first, second => {
console.log(second);
increase(second, third => {
console.log(third);
increase(third, fourth => {
console.log(fourth);
console.log('끝!');
})
})
})
})
결과로 아래와 같이 출력됩니다.
이러한 코드는 가독성도 떨어지고 로직을 변경하기도 어렵습니다.
이와 같은 구조를 콜백지옥(Callback Hell) 이라고 합니다.
웬만하면 지양해야하는 코드입니다.
일반적으로 콜백 지옥을 해결하는 방법에는 Promise 나 Async & Await를 사용하는 방법이 있습니다.
VELOPERT님의 리액트를 다루는 기술 - 개정판