
🖍️ 앞선 글에서 자바스크립트에서 동기와 비동기가 어떤 의미인지 공부했다.
이번에는 데이터 통신에서 동기와 비동기는 어떻게 이뤄지는지 공부해보자.

(출처)
동기적 데이터 통신은 요청을 보내면 그 후에 얼마만큼의 시간이 들어도 그 자리에서 응답을 받는다는 말이다.
즉, 요청을 보낸 클라이언트는 응답이 도착하기 전까지 아무것도 하지 못하는 상태가 된다.
동기적으로 데이터통신을 하면 웹페이지는 새로고침된다. 일부 영역만 따로 작업 할 수 없기 때문에 데이터를 받아오면 화면을 새롭게 그려야 하기 때문이다.
예전에 사전강의글에서 살펴본 것처럼 동기적 데이터통신을 하는 웹사이트의 예시로 최초의 웹사이트인 info.cern.ch가 있다.

링크를 눌러서 해당 주제의 데이터를 받아올 때마다 화면이 완전히 새롭게 바뀐다.
비동기 데이터 통신은 말 그대로 동시에 수행하지 않는다는 의미이다.
동기식과 반대로 요청을 보낸 후 언제 응답을 받는지는 중요하지 않다. 응답을 기다리지 않아도 되기 때문에 그동안에 다른 일을 처리할 수 있다.
비동기 데이터 통신은 웹페이지를 새로고침 하지 않아도 데이터를 불러 올 수 있다.
마찬가지로 사전강의에서 예로 들었던 나무위키 사이트가 있다.
링크를 누르면 페이지의 일부만 수정 될 뿐 전체적인 틀은 유지된다.
동기적 데이터 통신은 코드의 간결성과 직관성을 유지하고, 요청과 응답의 순서를 보장하기 때문에 에러처리가 비교적 쉽다.
하지만 요청과 응답이 반드시 이뤄져야하기 때문에 그동안에 다른 작업을 할 수 없다.
전체 페이지를 다시 로딩하기 때문에 서버와의 통신량이 많아지고, 자원과 시간이 낭비되며 웹페이지의 속도와 성능이 저하된다.
또 새로고침이 일어나면서 화면이 깜빡거리거나 데이터 통신이 끝낼 때 까지 멈추는 현상이 발생하여 사용자 경험이 떨어 질 수 있다.
이러한 단점 때문에 최근의 웹사이트들은 대부분 비동기방식으로 데이터통신을 한다.
비동기적 데이터 통신은 반대로 요청과 응답이 동시에 일어나지 않아도 되기 때문에 요청을 보낸 후 응답을 기다릴 필요 없이 다른 과정을 할 수 있다.
전체 페이지가 아닌 일부만 업데이트 할 수 있어서 웹페이지의 속도와 성능을 향상 시킬 수 있고, 서버와의 통신량이 적으니까 자원과 시간이 절약된다.
또 화면이 깜빡거리거나 멈추지 않기 때문에 사용자 경험을 개선시킬 수 있다.
자브스크립트에서 비동기적으로 데이터 통신을 하는 대표적인 예시가 Ajax(Asynchronous JavaScript And XML)이다.
XML (eXtensible Markup Language) : 다목적 마크업 언어로 태그 등을 이용하여 데이터의 구조를 작성 (출처)
HTTP 프로토콜을 이용하여 JSON, XML, HTML, 텍스트 파일 등 다양한 형태의 데이터를 주고 받을 수 있다. (출처)
전에 자바스크립트의 동기 / 비동기를 공부했을 때 본 것처럼, Ajax는 js engine이 아닌 브라우저의 webapi이기 때문에 비동기적으로 동작 할 수 있는 것이다.
AJAX를 사용하면 웹페이지가 로딩된 후에도 서버로부터 필요한 데이터만 요청하고 받아서 웹페이지를 동적으로 갱신할 수 있어, 웹 페이지의 일부분만을 업데이트할 수 있으므로, 전체 페이지를 새로고침하지 않아도 되고, 서버의 부하도 줄일 수 있다. (출처)
하지만, Ajax는 클라이언트가 서버에 데이터를 요청하는 클라이언트 풀링 방식을 사용하므로, 서버 푸시 방식의 실시간 서비스는 만들 수 없다.
클라이언트 풀링(client pooling) 방식이란 사용자가 직접 원하는 정보를 서버에게 요청하여 얻는 방식을 말하며, 서버 푸시(server push) 방식이란 사용자가 요청하지 않아도 서버가 알아서 자동으로 특정 정보를 제공하는 것을 의미한다. 사용하는 스마트 폰에서 각종 앱이 보내는 푸시 알림이 서버 푸시 방식의 대표적인 예이다. (출처)
Ajax의 가장 핵심적인 구성 요소는 XMLHttpRequest 객체이며, XMLHttpRequest 객체는 웹 브라우저가 서버와 데이터를 교환할 때 사용된다.
웹 브라우저가 백그라운드에서 계속해서 서버와 통신할 수 있는 것은 대부분의 주요 웹 브라우저는 XMLHttpRequest 객체를 내장하고 있기 때문이다.
웹 브라우저에서 사용자의 요청이 발생하면 Ajax는 자바스크립트로 XMLHttpRequest 객체를 생성하여 서버에 비동기 요청을 보낸다. 서버는 요청을 처리하고 XML이나 JSON형식으로 응답을 보내고, XMLHttpRequest 객체는 응답을 받아서 자바스크립트로 처리한다. 자바스크립트는 처리된 결과를 웹브라우저에 반영한다.
XMLHttpRequest는 서버와 상호작용하기 위해 사용하는 js의 빌트인 생성자이다. (생성자니까 new로 호출해야한다) 이것을 이용하면 서버로부터 데이터를 받아와 전체 페이지의 새로고침 없이도 페이지의 일부만 업데이트하는 비동기방식의 데이터통신을 수행 할 수 있다.
비동기 통신을 시작하면 서버와의 통신상태를 감지할 수 있다. 이 때 발생하는 이벤트는 이벤트핸들러에 등록할 수 있다.

주의깊게 봐야할 것은 load이다. 로드가 됐을 때 응답받은 값을 활용하여 dom을 조작 할 수 있다.
const rqs = new XMLHttpRequest();
rqs.open('get', 'https://dog.ceo/api/breeds/image/random');
rqs.addEventListener('load', function () {
alert('!')
});
rqs.send();
사용법은 위와 같다. XMLHttpRequest객체를 생성하고, .open()메소드를 사용하여 요청메소드와 요청을 보낼 주소를 입력한다. 세번째 인자까지 줄 수 있는데, 세번째 인자로 true를 주면 비동기방식으로 통신하고, false를 주면 동기적인 장식으로 통신한다. (기입하지 않으면 보통 true이다. )
send() 메소드는 작성된 Ajax 요청을 서버로 전달한다. 이 메소드는 전달 방식에 따라 인수를 가질 수도 안 가질 수도 있다. (데이터가 필요한 post요청의 경우 send안에 문자열로 넣어서 전송한다.)
생성된 객체의 상태가 load가 되면 이벤트를 처리한다.
받아온 응답을 처리하고, 요청상태를 확인 할 수 있는 여러 메소드는 여기에서 확인 할 수 있다. 이것들을 하나하나 정리하는 것 보다 필요할 때 찾아서 보는것이 더 효율적일것 같음으로 정리는 생략한다.
Ajax는 보안문제와 크로스 도메인 문제가 있을 수 있다.
(CORS, cors에 관해서는 nodejs에서 공부했다. -> 주소)
위에서 든 예시는 비교적 간단해서 잘 느껴지지 않지만, Ajax를 사용해서 통신을 하는것은 코드가 길고 복잡해진다. (출처, Ajax 콜백지옥 예시)
그것을 보안하여 만들어진 것이 Fetch이다.
Fetch API는 Request와 Response 객체, 그리고 기타 네트워크 요청에 관련된 것들을 사용하고, CORS와 HTTP Origin 헤더 행동 등 관련한 개념도 포함하고 있다.
XMLHttpRequest 대체자로 나온것이 fetch API이기 때문에 비동기 http 요청을 좀 더 쓰기 편하게 해준다.
ES6부터 만들어진 Javascript 내장 라이브러리로, Promise 기반으로 만들어졌다. (promise를 반환한다.)
내장라이브러리라서 별도의 설치(import)가 필요가 없고 Promise 기반이라서 데이터 다루기 편리하지만 JSON으로 변환을 해주어야 하는 과정이 필요하다.
fetch('https://dog.ceo/api/breeds/image/random')
.then((res) => {
return res.json();
})
.then((res) => {
console.log(res);
});
사용법은 위와 같지만, 아래처럼 async / await문법으로도 작성 할 수 있다.
async function trans() {
const jsonRes = await fetch('https://dog.ceo/api/breeds/image/random');
const res = await jsonRes.json();
console.log(res);
}
fetch('https://dog.ceo/api/breeds/image/random')
.then((res) => {
if (!res.ok) {
throw new Error('400 or 500');
}
return res.json();
})
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log('err 발생 : ' + err);
});
(출처: https://ghost4551.tistory.com/139 [프론트엔드 개발자의 기록 공간:티스토리])
추가로 fetch도 ajax처럼 동기데이터 통신을 하는 방법이 있나 찾아봤는데 동기적 통신이 필요하면 그냥 ajax를 쓰라고 한다.
fetch를 사용해도 되지만, 외부 라이브러리인 axios를 사용하면 fetch의 단점을 보안하고 더욱 편리하게 비동기 데이터 통신을 할 수 있다.
Axios는 브라우저, Node.js를 위한 Promise API를 활용하는 HTTP 비동기 통신 라이브러리이다.
Promise 기반이며, 크로스 브라우징 기반으로 브라우저 호환성이 뛰어나다. 자동으로 JSON데이터 형식으로 변환되며 요청 취소 및 타임아웃 설정이 가능한 등 fetch에 존재하지 않는 기능이 많다.
React나 vue에서 주로 사용하며 외부라이브러리이기 때문에 별도의 설치과정이 필요하다.
$ npm install axios<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script><script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
axios.get('https://dog.ceo/api/breeds/image/random')
.then((res) => {
console.log(res.data);
})
.catch((err) => {
console.log('err 발생 : ' + err);
});
axios사이트를 방문해보니 한글도 지원해주고 기본적으로 설명이 쉽고 자세하게 잘 되어있다. 필요할 때 마다 방문해서 보는것이 좋을 것 같다.
추가로, 멘토님은 타임아웃설정이 되는것이 axios의 큰 강점이라고 했다.
요청이 일정 시간 동안 응답을 받지 못할 경우 타임아웃을 설정할 수 있다.
한번씩 웹사이트를 이용하다 보면 화면이 하얗게 유지되거나 로딩중이라는 문구만 계속 떠있는것을 본적이 있을것이다. 그것이 타임아웃 설정이 되어있지 않기 때문이다.
이렇게 네트워크 요청이 블록되거나 오랜 시간이 걸리는 경우를 대비하여, 타임아웃이 발생하면 요청은 취소되고 콜백 함수나 Promise에서 에러가 반환되게하여 별도의 처리를 할 수 있다.
간단하게 요청하고 싶거나, 바닐라 js로만 통신을 하는 경우를 제외하면 axios를 사용하는것이 낫다. 좀 더 많은 기능들과 사용자(개발자)의 편의를 제공하기 때문이다.
혹은 개발시 주로 사용하는 프레임워크에서 제공하는 통신 라이브러리를 따라서 하는것이 보편적으로 쉽고 오류를 찾는것도 쉽다.
추가로 fetch vs axios의 장단점을 좀 더 분명하게 보고싶다면, 여기 혹은 여기의 마지막 부분에보면 표로 잘 비교되어 있다.