시작으로


Vue.js 프로젝트 개발을 진행하면서 비동기 처리에 따른 상태관리 및 DOM 처리 때문에 하루종일 애를 먹었다.
해결하고나니 간단한 문제였는데 당시에는 왜? 생각하지 못했는지 생각해봤다.

  • 비동기 처리에 대한 이해 부족
  • 라이프사이클 훅에 대한 이해 부족
  • 디자인 패턴 이해 부족

실무에서 나름 많이 사용했기에 익숙하다고(?) 자신했었지만 응용을 하니 확실히 깨달았다.

조금 안다고 자만하지말자.

그래서, 오늘은 비동기 처리에 대해 정리하려고 한다.


비동기 처리란 무엇인가?


[Javascript] 자바스크립트의 동작원리 포스팅을 참고하면 비동기 처리에 대한 이해를 도울 수 있다.

간단하게 말하면, 특정 명령을 끝날 때까지 기다리지 않고 다음 코드를 먼저 실행할 수 있도록 하는 자바스크립트의 특성이다.

이러한 자바스크립트의 비동기 처리로 인해 병렬처리를 한다고 오해하는 사람들이 있다. 절 대 아니므로 위의 포스터를 참고하길 바란다.


비동기 처리의 이해


Ajax 호출

가장 대표적인 비동기 처리는 AjaxsetTimeout() 이다. 예제를 통해 어떤 문제가 있는지 살펴보자.

// ajax get 요청을 통해 데이터를 응답받는다. 그 응답받은 데이터를 `res_data`에 담고 return한다. 
function asycFn() {
    var res_data;
	$.get('URL', function(res) {
		res_data = res;
	});
	return res_data;
}

console.log('시작');
console.log(asycFn());
console.log('');

위의 코드를 실행해보면

시작 -> -> undefined 로 출력이 될 것이다.
자바스크립트 동작원리를 간단하게 설명하자면 비동기처리로 호출되는 함수들은 Call Stack으로 쌓아서 하나하나씩 처리하지 않고 Callback Queue라는 곳에 보내진다. 그리고 비동기처리가 완료 되었더라도 Call Stack이 비어있을 때까지 대기했다가 비어 있으면 이벤트 루프를 돌려 콜백함수를 콜스택에 Call Stack에 넣는다.

음.. 실행순서가 시작 -> 까지는 이해했는데 왜 asycFn()함수의 값이 undefined으로 출력되지?

여기서 이상한 것을 감지했다면 당신은 고수

비동기로 호출한 함수는 마지막에 콜백함수Call Stack에 넣는다. 이게 가장 중요하다.

아까 설명했다시피 $.get()으로 데이터를 요청하고 받아올 때까지 기다리지 않고 다음 코드로 넘어간다.
여기서 return res_data;을 실행하기 때문에 res_data의 값은 undefined인 것이다.


setTimeout() 호출


자바스크립트의 비동기처리는 Callback Queue라는 곳에 보내진다고 했다. 이것은 코드 호출 순서를 이해하는데 중요하다.

Web API 중 하나인 setTimeout()을 예제로 실행해보자.

당연히 지정한 시간만큼 기다렸다가 실행되기 때문에 1 -> 3 -> 2 순서로 출력되는 것을 예상할 수 있다.

console.log('1');
setTimeout(function() {
	console.log('2');
}, 1000);
console.log('3');

image


그렇다면 지정한 시간을 0초로 하면 어떻게 출력될까?

console.log('1');
setTimeout(function() {
	console.log('2');
}, 0);
console.log('3');

image

위의 실행순서와 마찬가지로 1 -> 3 -> 2 순서로 출력되고 있다. 아까 설명했듯이 자바스크립트의 비동기처리는 처리시간과 관계없이 무조건 Callback Queue으로 보내진다. 그리고 Call Stack이 비어있으면 스택에 올려 처리한다.

이러한 자바스크립트의 동작원리를 이해하는 것은 정말 중요하다.


Callback 함수로 비동기처리의 문제 해결하기


앞의 Ajax의 예제를 보면 서버에서 받아온 데이터로 후속 작업을 하고싶을 때 콜백(callback) 함수를 사용한다.

콜백(callback)를 사용하면 특정 로직이 끝났을 때 원하는 동작을 실행시킬 수 있다.

function asycFn(callback) {
  var res_data;
	$.get('URL', function(res) {
		callback(res);
	});
}

asycFn(function(data){
  console.log(data); // // $.get()의 결과값이 data에 전달됨
})