[JavaScript]

[JavaScript] 동기/비동기 처리, 콜백함수

두두만두 2023. 4. 8. 14:40

동기(synchronous)/비동기적(Asynchronous)

특정 코드의 연산이 끝날 때까지 코드의 실행을 멈추지 않고 다음 코드를 실행하는 JavaScript의 특성을 의미한다.

 

동기 처리

JavaScript의 동기 처리란 우선순위 작업이 끝날 때까지 멈춘 상태를 유지하고 준비상태가 되기 때문에 다른 작업을 할수가  없다.

 

비동기 처리

JavaScript단일 스레드, 동기식으로 동작한다. 특정 코드의 연산이 끝날 때까지 코드의 실행을 멈추지 않고 응답에 관계없이 다음 동작이 실행되는 방식이다. 동시에 여러가지 작업을 처리하며, 기다리는 과정에 다른 함수를 호출수도 있다.

비동기 처리는 왜 필요한가?

웹 사이트 사용자들은 응답에 답이 없고 느린 웹 사이트를 원하지 않는다. 그래서 JavaScript가 웹사이트에서 비동기적으로 동작할 수 있어야 한다.

 

비동기 처리의 예시

(ajax 코드)

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

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

여기서 $.get()이 ajax 통신을 하는 부분이며, "https://domain.com"에 HTTP GET 요청을 보내 1번 상품(product) 정보를 요청하는 코드 이다. 쉽게 이야기 하면 지정된 URL에 데이터를 보내달라는 요청을 날리는 것이다.

 

서버에 받아온 데이터를 tableData라는 변수에 저장한다. 그럼 getData() 호출 하게 된다면 받아온 데이터가 찍혀야 한다. 하지만 결과는 undefined이다.

 

이유는  $.get()로 데이터를 요청하고 받아 오기까지 기다려주지 않고 다음 코드인 return tableData;를 실행했기 때문이다.  따라서, getData()의 결과 값은 초기 값을 설정하지 않은 tableData의 값 undefined를 출력한다.

 

(setTimeout 함수 이용)

// #1
console.log("Hello");

// #2
setTimeout(function() => {
  console.log("Good Bye");
}, 3000);

// #3
console.log("Hello Again");

위 코드를 보면 다음과 같은 결과 값이 나올 거라고 생각 할 것이다.

"Hello"
1초 후  "Good Bye"
"Hello Again"

하지만 실제 출력 되는 값은 다음과 같은 값으로 출력된다.

"Hello"
"Hello Again"
1초 후  "Good Bye". 

setTimeout() 역시 비동기 방식으로 실행되기 때문에 1초 후 코드를 수행하는 것이 아닌 실행하고 나서 바로 다음 코드인 console.log("Hello Again"); 실행 되었다. 따라서 "Hello", "Hello Again"를 먼저 출력하고 1초 후 "Good Bye"가 출력된다.

 

JavaScript 비동기 처리 방식에 의해 문제들을 콜백(CallBack) 함수를 이용해 개선 할 수 있다.

 

콜백(CallBack)함수

콜백 함수는 비동기 방식의 함수로 다른 함수의 매개변수로 함수를 전달하고 어떤 이벤트가 발생한 후 매개변수로 전달한 함수가 다시 호출 되는 것을 의미한다.

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

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

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

 

콜백 함수의 동작 방식을 비유하자면 우리가 맛집에 가기 위해 줄을 서지 않고 대기자 명단에 이름과 번호를 적은 후 다른 곳을 가서 구경을 하고 있다 자리가 나오면 연락이 온다. 연락이 온 시점부터 콜백 함수가 호출되는 시점은 같다.

식당에 자리가 비어있는지 확인 할 것도 없이 자리가 준비된 시점(데이터가 준비된 시점)에 원하는 동작을 수행할 수 있다. 

 

콜백 지옥(CallBack Hell)

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

콜백함수는 순차적으로 이어져서 좋다는 장점이 있지만 코드가 많아지면 읽는 가독성과 관리가 어려워진다.

이것이 계속 이어지게 되면 콜백 지옥(CallBack Hell)이라고 부른다. 콜백 지옥을 해결하기 위한 방법으로는 Promise, Async를 사용하는 방법이 있다. BUT!! 코딩 패턴으로만 콜백 지옥을 해결하기 위해서는 콜백 함수를 분리해주면 된다.