비동기 통신과 AJAX
(동기 비동기의 개념, 차이,장단점, 예시, 콜백함수, 콜백지옥)
데이터를 받는 방식인 동기와 비동기 그리고 AJAX.
각각이 무엇이며, 어떤 특징이 있는지 예시를 통해 알아본다.
0. 동기와 비동기 개념
동기(synchronous : 동시에 일어나는)
- 요청을 하면 (바로) 응답을 받는다는 의미. 말 그대로 동시에 일어난다는 뜻. 요청과 그 결과가 동시에 일어난다는 약속. 바로 요청을 하면 시간이 얼마가 걸리던지 요청한 자리에서 결과가 주어져야 한다.
-> 요청과 결과가 한 자리에서 동시에 일어남.
-> A노드와 B노드 사이의 작업 처리 단위(transaction)를 동시에 맞추겠다.
비동기(Asynchronous : 동시에 일어나지 않는)
- 동시에 일어나지 않는다를 의미. 요청과 결과가 동시에 일어나지 않을거라는 약속이다. 요청과 응답이 다른 시간대 존재하기 때문에, 요청내용에 대해 지금 바로 혹은 당장 응답받지 않아도 된다. (바로 응답이 와도 되고!)
-> 요청한 그 자리에서 결과가 주어지지 않음.
-> 노드 사이의 작업 처리 단위를 동시에 맞추지 않아도 된다.
1. 동기와 비동기 장단점
동기와 비동기는 상황에 따라서 각각의 장단점이 있다.
동기방식은 설계가 매우 간단하고 직관적이지만 결과가 주어질 때까지 아무것도 못하고 대기해야 하는 단점이 있고,
비동기방식은 동기보다 복잡하지만 결과가 주어지는데 시간이 걸리더라도 그 시간 동안 다른 작업을 할 수 있으므로 자원을 효율적으로 사용할 수 있는 장점이 있다.
페이지 리로드의 경우, 전체 리소스를 다시 불러와야하는데 이미지, 스크립트 , 기타 코드등을 모두 재요청할 경우 불필요한 리소스 낭비가 발생하게 되지만 비동기식 방식을 이용할 경우 필요한 부분만 불러와 사용할 수 있으므로 매우 큰 장점이 있다.
동기는 추구하는 같은 행위(목적)가 동시에 이루어지며,
비동기는 추구하는 행위(목적)가 다를 수도 있고, 동시에 이루어지지도 않는다고 요약할 수 있겠다.
2. 동기와 비동기 예시
동기의 예시
C언어의 scanf()와 Java의 Scanner 객체의 next()메서드 같이 사용자의 입력을 받는 함수 등, 일반적으로 사용하는 함수들은 대부분 동기적 방식. 아래 예시를 보자.
Scanner sc = new Scanner(System.in); int num = sc.nextInt();
sc.nextInt() 결과 사용자가 입력을 하면, 그 값은 num이라는 변수에 담긴다.
즉, nextInt() 메서드를 호출하고 그 결과를 자신이 직접 처리!
따라서 위의 코드는 동기적 방식이라 할 수 있다.
비동기 예시, AJAX
비동기 처리의 가장 기본적인 사례는 제이쿼리의 ajax이다.
화면에 표시할 이미지나 데이터를 서버에서 불러와 표시할 때, ajax 라는 네트워크 통신 기술로 클라이언트가 요청한 데이터를 서버로부터 가져온다. 아래 ajax 코드를 살펴보자.
function getData() {
var tableData;
$.get('https://domain.com/products/1', function(response) {
tableData = response;
});
return tableData;
}
console.log(getData());
==================================================================
결과 : undefined
여기서 3번 째 줄의 $.get()이 바로 ajax 통신을 하는 부분이다.
https://domain.com 에 HTTP GET 요청으로 1번 상품(product) 정보를 요청하는 코드.
지정된 URL에 ‘데이터 하나 보내주세요' 라는 요청을 날리는 것과 같다.
그렇게 서버에서 받아온 데이터는 response 인자에 담기고,
tableData = response; 로 받아온 데이터를 tableData라는 변수에 저장한다.
그럼 이제 이 getData()를 호출하면 어떻게 될까? 받아온 데이터가 뭐든 일단 뭔가 찍히겠지?
그치만 결과는 undefined가 나온다. 왜일까?
이유는 $.get()로 데이터를 요청하고, 받아올 때까지 기다려주지 않고 다음 코드인 return tableData;를 실행했기 때문이다. 따라서 getData()의 결과 값은 초기 값을 설정하지 않은 tableData의 값 undefined를 출력한다.
이렇게 특정 로직의 실행이 끝날 때까지 기다려주지 않고 나머지 코드를 먼저 실행하는 것이 비동기 처리이다.
자바스크립트에서 비동기 처리가 필요한 이유를 생각해보면, 화면에서 서버로 데이터를 요청했을 때 서버가 언제 그 요청에 대한 응답을 줄지도 모르는데 마냥 다른 코드를 실행 안 하고 기다릴 순 없기 때문이다. 위에선 간단한 요청 1개만 보냈지만, 만약 100개를 보낸다면? 비동기 처리가 아닌 동기 처리라면 코드 실행하고 기다리고, 실행하고 기다리고.. 아마 웹 애플리케이션을 실행하는데 수십 분은 걸릴 것이다. 다음 비동기 예시를 보자.
비동기 예시, setTimeout()
다음은 또 다른 비동기 방식의 예시인 JS의 setTimeout() 함수이다.
setTimeout()은 Web API의 한 종류이다. 코드를 바로 실행하지 않고 지정한 시간만큼 기다렸다가 로직을 실행한다. 다음 예시 코드를 보자.
setTimeout(boo, 3000);
function boo(){
console.log("2");
}
console.log("1");
setTimeout() 함수를 호출하면 3초 뒤에 boo() 함수가 수행되는 코드이다.
setTimeout() 함수를 호출한 후 3초라는 시간이 흘러야 boo() 함수가 수행되며,
이 시간 동안 프로그램은 다음 코드를 읽기 때문에 위 코드는 콘솔에 1, 2 순서로 출력이 된다.
여기서 boo()함수를 setTimeout()함수의 콜백(callback)함수라고 한다.
콜백 함수란, 비동기 방식에서 어떤 수행이 완료되었을 때(event가 발생했을 때) 수행해야 할 함수이다. 비동기 방식에서는 함수를 호출한 쪽에서 수행 결과를 직접 처리하지 않고 콜백 함수를 통해 수행 결과를 처리한다.
3. 콜백함수, 비동기 처리 방식의 문제점 해결
앞에서 자바스크립트 비동기 처리 방식에 의해 야기될 수 있는 문제들을 살펴봤다.
이제 이 문제들은 콜백(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에 전달됨
});
이렇게 콜백함수를 사용하면 특정 로직이 끝났을 때 원하는 동작을 실행시킬 수 있다.
콜백 함수의 동작 방식은 식당 자리 예약에 비유할 수 있다.
주말 점심, 맛집을 찾아가면 보통 자리가 없다. 그래서 대기자 명단에 이름을 써두고, 그 맛집에 자리가 날 때까지 주변을 돌아다닌다. 만약 식당에서 자리가 생기면 자리가 났다고 연락이 온다. 그 전화를 받는 시점이, 여기서의 콜백 함수가 호출되는 시점과 같다. 손님 입장에서는 자리가 날 때까지 식당에서 기다리지 않고 근처 가게에서 잠깐 쇼핑을 할 수도 있고, 아니면 다른 식당 자리를 알아볼 수도 있다.
자리가 났을 때만 연락이 오기 때문에 미리 가서 기다릴 필요도 없고, 직접 식당 안에 들어가서 자리가 비어 있는지 확인할 필요도 없다. 자리가 준비된 시점, 즉 데이터가 준비된 시점에서만 우리가 원하는 동작(자리에 앉는다, 특정 값을 출력한다 등)을 수행할 수 있다. 그래서 다음과 같은 문제점이 생기기도 한다.
4. 콜백 지옥 (Callback hell)
콜백 지옥은 비동기 처리 로직을 위해 콜백 함수를 연속해서 사용할 때 발생하는 문제다. 아래 코드를 보자.
$.get('url', function(response) {
parseValue(response, function(id) {
auth(id, function(result) {
display(result, function(text) {
console.log(text);
});
});
});
});
웹 서비스를 개발하다 보면 서버에서 데이터를 받아와 화면에 표시하기까지 인코딩, 사용자 인증 등을 처리해야 하는 경우가 있다. 만약 이 모든 과정을 비동기로 처리해야 한다고 하면, 위와 같이 콜백 안에 콜백을 계속 무는 형식으로 코딩을 하게 된다. 이러한 코드 구조는 가독성도 떨어지고 로직을 변경하기도 어려운데, 이와 같은 코드 구조를 콜백 지옥이라고 한다.
이를 해결하는 방법으로는 Promise, Async를 사용하거나, 각 콜백 함수를 분리하는 코딩 패턴을 사용하면 된다.
5. 비동기적 처리의 이유
정리해보자. 비동기 처리가 필요한 이유는 무엇일까?
제이쿼리의 ajax 통신과 같이 원하는 데이터를 서버로 부터 받아오는 방식을 취하는 어플리케이션을 만들었다고 가정해 본다. 서버로부터 데이터를 받아와서 해당 데이터를 처리해야 하므로, 데이터를 받아오는 코드는 전체 코드중의 최상단에 위치해야 할 것이다. 그런데 만약 비동기적 처리를 하지 않고 동기적 처리를 하는 어플리케이션이라면?
서버로부터 데이터를 받아오는 코드의 실행이 완전히 끝난 뒤에 이후의 코드를 처리할 것인데,
받아오는 데이터의 크기가 작고 갯수가 적다면 크게 상관없을 수 있지만 받아오는 데이터의 크기가 크고 많다면?
모든 데이터의 수신을 완료한 다음 나머지 코드를 실행할 수 있으므로, 데이터를 받아오는 동안에 프로그램은 사실상 멈춰있는것과 다름없다. 언제 끝날지도 모르는 요청때문에 나머지 코드를 실행시키지 못하고 사용자를 기다리게 하는 아주 불친절한 프로그램이 될 것. 데이터를 수신해야할 때마다 기다려야 한다면 누구도 그 어플리케이션을 사용하고 싶지 않을것이다. 이러한 사용자의 불편을 없애기 위해, 데이터의 수신과 기다려야하는 코드들을 비동기적으로 처리한다.
위에서 언급한 AJAX를 사용하는 이유도 이와 같다. 단순하게 WEB화면에서 무언가 부르거나 데이터를 조회하고 싶을 경우, 페이지 전체를 새로고침하지 않기 위해 사용한다고 볼 수 있다.
기본적으로 HTTP 프로토콜은 클라이언트쪽에서 Request를 보내고 서버쪽에서 Response를 받으면 이어졌던 연결이 끊기게 되어있다. 그래서 화면의 내용을 갱신하기 위해서는 다시 request를 하고 response를 하며 페이지 전체를 갱신하게 된다. 하지만 이렇게 할 경우, 엄청난 자원낭비와 시간낭비를 초래하고 말 것이다.
AJAX는 HTML 페이지 전체가 아닌 일부분만 갱신할 수 있도록 XMLHttpRequest객체를 통해 서버에 request한다. 이 경우, JSON이나 XML형태로 필요한 데이터만 받아 갱신하기 때문에 그만큼의 자원과 시간을 아낄 수 있다.
물론 AJAX의 단점 또한 존재한다.
히스토리 관리가 되지 않고,
페이지 이동없는 통신으로 인한 보안상의 문제,
연속으로 데이터를 요청 시, 서버 부하,
XMLHttpRequest를 통해 통신하는 경우, 사용자에게 아무런 진행 정보가 주어지지 않음(요청이 완료되지 않았는데 사용자가 페이지를 떠나거나 오작동할 우려가 발생하게 된다.),
AJAX를 쓸 수 없는 브라우저에 대한 문제 이슈,
HTTP 클라이언트 기능 한정,
지원하는 Charset이 한정,
Script로 작성되므로 디버깅이 용이하지 않음,
동일-출처 정책으로 인하여 다른 도메인과는 통신이 불가능(Cross-Domain문제) 등이 있다.
'🤹🏻♀️ 자바스크립트 𝗝𝗮𝘃𝗮𝘀𝗰𝗿𝗶𝗽𝘁' 카테고리의 다른 글
[JS] JSON .parse VS .stringify 차이점 (0) | 2022.11.12 |
---|---|
[javascript] 동기, 비동기 (예제) (0) | 2022.11.11 |
[javascript] 자바스크립트 문자열 정렬 (오름차순, 내림차순) (0) | 2022.11.10 |
[javascript] 자바스크립트 숫자 배열 정렬 (0) | 2022.11.10 |
[javascript] 자바스크립트 랜덤 점심메뉴 고르기 (0) | 2022.11.09 |
댓글