Ajax를 공부하다가 브라우저의 Web API인 XMLHttpRequest, 자바스크립트에서 비동기를 맨 처음 배웠을 때 가장 먼저 다뤘었던 fetch, 그리고 이번에 프로젝트 할 때 사용했던 axios와는 어떤 차이가 있는지 궁금해져서 공부하다가 포스팅을 쓰게 되었다.
공통점이 있다면 클라이언트에서 서버에 데이터 요청할 때 사용하는 API인거 아니야?!!
알고보면 다 차이가 있다구~
이번 포스팅에서는 Ajax의 의미가 무엇인지 먼저 알아보고, XMLHttpRequest와 jQuery, fetch, axios의 특징을 순서대로 정리해보려고 한다.
Ajax(Asynchronous Javascript and XML)의 약자이다.
Ajax 이전에는 서버에서 HTML 파일을 통째로 받고, 일부가 수정되면 HTML을 다시 통째로 받아오는 방법을 사용했다. 그래서 일부가 수정되었는데도 새로 받아온 HTML을 처음부터 싹 다 렌더링 하느라 화면이 깜빡이는 현상도 발생했다고 한다.
그리고 무엇보다 비동기가 아닌 동기적인 방식으로 서버에서 데이터를 받아왔기 떄문에, 데이터를 요청하면 응답이 올 때까지 다음 작업을 처리할 수 없는 블로킹이 발생했다고 한다.
Ajax는 비동기 방식이기 때문에 이런 블로킹이 발생하지 않고, 변경된 부분만 서버에 요청하기 때문에 화면 깜빡임도 없고 성능 측면에서도 (HTML을 부분 업데이트될 때 마다 싹다 받는) 이전 방식에 비해 개선되었다고 한다. 페이지를 reload하는 게 아니라 DOM 조작을 하여 변경사항을 반영하기 때문에 이러한 부분 업데이트가 가능해지는 것이다.
아래는 순수 자바스크립트의 XMLHttpRequest를 이용하여 GET 요청을 하는 예시 코드이다.
document.addEventListener("DOMContentLoaded", function() {
document.getElementById("loadData").addEventListener("click", function() {
// XMLHttpRequest 객체 생성
var xhr = new XMLHttpRequest();
xhr.open("GET", "https://jsonplaceholder.typicode.com/posts/1", true);
// 데이터 수신이 성공적으로 완료됐을 때의 이벤트 핸들러
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 400) {
var data = JSON.parse(xhr.responseText);
document.getElementById("result").innerHTML = `
<h2>${data.title}</h2>
<p>${data.body}</p>
`;
} else {
document.getElementById("result").innerHTML = "데이터를 불러오는데 실패했습니다.";
}
};
// 에러 발생 시의 이벤트 핸들러
xhr.onerror = function() {
document.getElementById("result").innerHTML = "데이터를 불러오는데 실패했습니다.";
};
// XMLHttpRequest 요청 전송
xhr.send();
});
});
jQuery를 사용하면 XMLHttpRequest를 이용하여 작성할 때보다 깔끔한 코드로 Ajax를 사용할 수 있다고 한다.
$(document).ready(function(){
$("#loadData").click(function(){
$.ajax({
url: "https://jsonplaceholder.typicode.com/posts/1", // 예시 API 엔드포인트
type: "GET",
dataType: "json",
success: function(data) {
$("#result").html(`
<h2>${data.title}</h2>
<p>${data.body}</p>
`);
},
error: function(error) {
$("#result").html("데이터를 불러오는데 실패했습니다.");
}
});
});
});
훨씬 짧고 깔끔해졌다.
하지만 XMLHttpRequest나 jQuery를 이용하면 Promise 기반의 동작이 아니어서 response를 처리하기가 까다롭다는 단점이 있다.
그렇다면 Promise 기반의 비동기 통신 방법을 사용하면 response 처리가 좀 더 편하겠지?
참고: https://developer.mozilla.org/ko/docs/Web/API/Fetch_API/Using_Fetch
fetch는 ES6에서 Promise와 함께 등장한 자바스크립트 내장 라이브러리이다.
Promise 형태의 response를 return 해주므로 response 처리도 보다 간편하다.
document.addEventListener("DOMContentLoaded", function() {
document.getElementById("loadData").addEventListener("click", function() {
fetch("https://jsonplaceholder.typicode.com/posts/1")
.then(response => {
if (!response.ok) {
throw new Error("Network response was not ok");
}
return response.json();
})
.then(data => {
document.getElementById("result").innerHTML = `
<h2>${data.title}</h2>
<p>${data.body}</p>
`;
})
.catch(error => {
document.getElementById("result").innerHTML = "데이터를 불러오는데 실패했습니다.";
});
});
});
이제 좀 코드가 익숙하군.
response.json()은 참고로 JSON으로 변환하는 메서드가 아니라 JSON을 자바스크립트 객체로 변환해주는 메서드이다. 헷갈리기 쉬우니 짚고 넘어가기!
그런데 fetch를 여전히 지원하지 않는 브라우저도 있다고 한다.
fetch보다 브라우저 호환성도 좋고 기능도 더 많이 제공하는 라이브러리가 있다.
그것은 바로 axios!
참고: https://axios-http.com/kr/docs/intro
axios는 fetch보다 더 많은 기능을 제공하기 때문에 특히 실무에서 선호하는 경향이 있다고 한다.
생각해보면 axios를 쓸 때는 response.json()을 사용한 기억이 없다.
axios는 알아서 자체적으로 일반 자바스크립트로 변환해주는 똑똑한 기능을 가지고 있기 때문이다. 요청 본문에 자바스크립트 객체를 담을 때도 알아서 JSON으로 변환해준다.
fetch와 마찬가지로 Promise를 return하므로 응답 처리도 간편하다.
document.addEventListener("DOMContentLoaded", function() {
document.getElementById("loadData").addEventListener("click", function() {
axios.get("https://jsonplaceholder.typicode.com/posts/1")
.then(response => {
const data = response.data;
document.getElementById("result").innerHTML = `
<h2>${data.title}</h2>
<p>${data.body}</p>
`;
})
.catch(error => {
document.getElementById("result").innerHTML = "데이터를 불러오는데 실패했습니다.";
});
});
});
하지만 내장 라이브러리가 아니어서 별도로 설치하고 import를 해주어야 하는 잠시 견뎌야 할 귀찮음이 존재하는 건 사실이다. 그럼에도 불구하고 기능이 다양하니까 더 많이 사용하는 것이라 생각한다.
이번에 프로젝트를 하면서 나도 비동기 통신에 axios를 사용했다. 그 때 GET 요청 body에 데이터를 담으려고 하다가 오류가 난 적이 있다. 알고보니 GET 요청에서는 데이터를 body에 담는 POST와 달리 데이터를 쿼리 파라미터에 담아야 한다고..! 하지만 fetch에서는 GET 요청인데도 body에 데이터를 담아도 이런 오류가 나지 않는다고 한다. axios에서 이런 오류를 잡아주는 기능은 참 고맙게 여겨졌다.
그리고 이 포스팅을 쓰면서 알게된 거지만 fetch는 네트워크 오류에 대해서만 reject를 반환하고, HTTP 오류에 대해서는 resolve를 반환한다고 한다. 아니 이건 좀 너무 치명적인걸?
프로젝트를 하면서 경험했지만 HTTP 오류는 개발 단계에서 4XX이든 5XX이든 밥 먹듯이 떴는데 그걸 catch해주지 못했다면..? fetch의 치명적인 단점이라고 생각이 들고, 어쩌면 실무에서 axios를 사용을 선호하는 결정적인 이유가 될 수 있겠다는 생각도 든다.
다만 React Native처럼 버전이 자주 변경되는 프레임워크에서는 내장 라이브러리인 fetch가 axios보다 안정적일 수도 있겠다는 어느 개발자분의 포스팅도 보게 되었다.
참고: https://velog.io/@kysung95/%EA%B0%9C%EB%B0%9C%EC%83%81%EC%8B%9D-Ajax%EC%99%80-Axios-%EA%B7%B8%EB%A6%AC%EA%B3%A0-fetch
toy 프로젝트에서는 굳이 axios를 사용하지 않아도 javascript 내장 라이브러리인 fetch로 간편하게 처리할 수 있겠지만, 프로젝트 규모가 커지고 다양한 기능을 필요로 하거나 HTTP 오류 처리가 중요하다면 axios를 사용하는 편이 더 낫겠다.
좋은 글 감사합니다. 자주 올게요 :)