💡클라이언트와 서버간 비동기 통신 방법에는 크게 세가지가 있다.
- XMLHttpRequest 객체
- Fetch API
- jquery의 ajax 통신
지난 1부에서는 XMLHttpRequest 객체 사용법에 대해 알아봤다.
[Javascript] 클라이언트와 서버간의 비동기통신에 대해 알아보자. / 1부
1. Ajax란? 'Asynchronous JavaScript and XML'의 약자다. Ajax란 자바스크립트를 사용하여 브라우저가 서버에게 비동기 방식으로 데이터를 요청하고, 서버가 응답한 데이터를 수신하여 웹페이지를 동적으로
ururuwave.tistory.com
2부에서는 Fetch API에 대해 알아보자!
Fetch API에 대해 알아보니 promise 객체를 이용한다고 한다.
promise 객체는 전통적인 콜백 패턴으로 비동기 처리를 하는 것을 개선하기 위해 만들어졌다고 한다.
promise, 콜백 함수가 뭔지 같이 알아봐야 겠다.
1. 함수 선언법
JavaScript에서 함수를 선언하거나 정의하는 방법에는 크게 세가지가 있다.
함수 선언문, 함수 표현식, 그리고 화살표 함수다.
각각 상황과 요구사항에 따라 다르게 사용된다.
추후 포스팅하여 링크를 달 예정.
2. 콜백함수
1) 개념
콜백함수는 다른 함수에 인자로 전달되는 함수다.
특정 코드 또는 이벤트가 완료된 후 실행되도록 한다.
// 콜백 함수 정의
function displayMessage() {
console.log("2초가 지났습니다!");
}
// setTimeout을 사용하여 2초 후에 콜백 함수 실행
setTimeout(displayMessage, 2000);
displayMessage 콜백 함수가 setTimeout의 매개변수로 쓰인다.
주로 비동기적인 작업(ex.파일읽기, 서버 요청 등)이 완료된 후 결과를 처리할 때 사용한다.
2) 장점
- 단순성 : 초기 JavaScript에서 비동기 처리를 구현하는 간단하고 직관적인 방법이다.
- 유연성 : 함수를 다른 함수에 인자로 전달하여, 동적으로 함수의 행동을 변경할 수 있다.
3) 단점
콜백 지옥
: 중첩된 콜백으로 코드가 복잡해지고 가독성이 떨어지는 문제.
순차적으로 작업을 수행하며 중첩된 콜백 형태로 구현되어 있다.
이런 경우 오류의 원인을 찾기 위해 여러 콜백 레벨을 거슬러 올라가야해서 디버깅 하기가 어렵다.
그리고 에러처리가 복잡해질 수 있다.
콜백지옥을 피하기 위해서는 promise나 async/await와 같은 기능을 사용하면 된다.
/*콜백지옥 코드 예시*/
// 비동기 작업을 수행하는 함수들
function doFirstTask(callback) {
setTimeout(() => {
console.log("첫 번째 작업 완료");
callback();
}, 1000);
}
function doSecondTask(callback) {
setTimeout(() => {
console.log("두 번째 작업 완료");
callback();
}, 1000);
}
function doThirdTask(callback) {
setTimeout(() => {
console.log("세 번째 작업 완료");
callback();
}, 1000);
}
// 콜백 지옥
doFirstTask(() => {
doSecondTask(() => {
doThirdTask(() => {
console.log("모든 작업 완료");
});
});
});
3. Promise
콜백 패턴으로 비동기처리를 할 때, 나쁜 가독성, 에러 처리의 곤란함으로 여러 개의 비동기 처리를 한번에 처리하기에 한계가 있었다.
프로미스는 비동기처리를 위한 패턴이다.
1) 개념
Promise는 비동기 처리 상태와 처리 결과를 관리하는 객체다.
2) 생성
: new Promise()생성자를 사용해 Promise 객체를 생성한다.
이 생성자는 'resolve'와 'reject' 두 개의 함수를 매개변수로 받는다.
/*프로미스 생성 코드 예시*/
const promise = new Promise((resolve, reject)=> {
//promise 함수의 콜백 함수 내부에서 비동기 처리를 수행한다.
if(/*비동기 처리 성공*/){
resolve('result')
} else {/*비동기 처리 실패*/
reject('failure reason');
}
});
생성된 직후 프로미스는 기본적으로 pending 상태다. 이 후 비동기 처리가 수행되면 비동기 처리 상태가 바뀐다.
3) 후속 처리 메서드
프로미스의 비동기 처리 상태가 변화하면 resolve냐, reject냐에 따라 후속 처리를 해야한다.
then() , catch(), finally() 메서드를 사용한다.
1️⃣ 'then' 메서드 (Promise.prototype.then)
then 메서드는 두 개의 콜백 함수를 인수로 받을 수 있다.
▪️ 첫 번째 콜백 함수는 프로미스가 fulfilled상태(resolve함수 호출)가 되면 호출된다.
--> 콜백 함수는 프로미스의 비동기 처리 결과를 인수로 전달받는다.
▪️ 두 번째 콜백 함수는 프로미스가 rejected상태(reject함수 호출)가 되면 호출된다.
--> 콜백 함수는 프로미스의 에러를 인수로 전달받는다.
2️⃣ 'catch' 메서드 (Promise.prototype.catch)
catch 메서드의 콜백함수는 Promise가 rejected상태인 경우만 호출된다.
❗then 메서드로 reject함수를 호출할지 말지는 선택적이다.
일반적으로 오류 처리는 'catch'메서드를 사용한다.
왜냐하면, catch를 사용해야 이전 then 블록에서 발생한 예외를 잡아 다음 블록으로 전파되어 체이닝 동작이 수행되기 때문이다.
then에서는 프로미스 성공 로직을 다루고 catch에서 프로미스 실패 로직을 다루는 것이 가독성과 유지보수성면에서 좋다.
3️⃣'finally' 메서드 (Promise.prototype.finally)
finally메서드는 프로미스의 성공 또는 실패와 상관없이 무조건 한 번 호출된다.
프로미스 상태와 상관없이 공통적으로 수행해야할 처리 내용이 있을 때 유용하다.
4) 콜백 지옥 코드를 Promise로 개선해보자.
위에 있는 콜백 지옥 예시 코드를 Promise로 바꿔보자.
function doFirstTask() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("첫 번째 작업 완료");
resolve();
}, 1000);
});
}
function doSecondTask() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("두 번째 작업 완료");
resolve();
}, 1000);
});
}
function doThirdTask() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("세 번째 작업 완료");
resolve();
}, 1000);
});
}
// Promise 체이닝을 사용하여 순차적으로 작업 수행
// then을 여러번 사용하여 가독성을 높임.
doFirstTask()
.then(doSecondTask)
.then(doThirdTask)
.then(() => {
console.log("모든 작업 완료");
})
.catch(error => {
console.error("에러 발생:", error);
});
4. Fetch API
대망의 fetch를 알아볼 차례다.
fetch를 이해하기 위해 콜백함수와 promise에 대해 공부를 했다.
1) Fetch API의 등장
XMLHttpRequest의 한계점을 해결하기 위해 2015년 도입되었다.
(복잡한 사용법, 콜백 기반으로 콜백 지옥 초래, 불편한 예외 처리)
현재는 개발자들 사이에서 표준적인 비동기 HTTP 요청 방법으로 자리 잡았다.
Fetch API는 기존 XMLHttpRequest의 단점을 개선한 것에 더불어 서버로부터 데이터를 조금씩 받아와서 처리하는 스트리밍 기능도 지원한다.
2) 개념
Fetch API는 XMLHttpRequest 객체와 마찬가지로 HTTP 요청 전송 기능을 제공하는 Web API다.
Promise 기반으로 동작하기 때문에 XMLHttpRequest보다 코드를 더 간결하고 읽기 쉽게 만들 수 있다.
또한, catch 블록을 사용하여 예외 처리를 명확하게 할 수 있다.
그래서 요즘 웹 애플리케이션에서는 Fetch를 사용하는 경향이 있다.
3) 비동기적 파일 업로드 예시
기존 동기식 파일 업로드 방식은 파일 업로드 후 페이지 전체를 새로고침 해야했지만 비동기적으로 파일을 업로드하게 되면 페이지를 새로고침 하지 않고도 서버에 파일을 전송할 수 있다.
또한 비동기 방식은 파일 업로드가 백그라운드에서 수행되어 사용자는 업로드 중에도 다른 작업을 계속할 수 있다.
대용량 파일을 업로드할때 비동기적 파일 업로드를 하는 것이 좋다.
<HTML 코드>
//사용자가 파일을 선택할 수 있도록 input 태그 만들고
//업로드 이벤트를 발생시키는 button 태그 만들음
<input type="file" id="fileInput">
<button id="uploadButton">Upload</button>
<JavaScript 코드>
document.getElementById('uploadButton').addEventListener('click', () => {
const fileInput = document.getElementById('fileInput');
const file = fileInput.files[0]; // 사용자가 선택한 첫 번째 파일
const formData = new FormData();
//formData는 JavaScript의 내장 객체다.
//키-값 쌍을 구성하여 서버로 데이터를 전송할 수 있게 도와줌.
formData.append('file', file); // 'file'은 서버에서 기대하는 필드 이름
fetch('https://example.com/upload', {
// 서버 측에서 설정한 특정 API엔드포인트
// 이 URL은 일반적인 웹페이지 URL과는 다르고 서버에서 데이터를 받아 처리하는데 사용하는 주소다.
method: 'POST', //요청 메서드
body: formData, //요청본문
})
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json(); //응답을 JSON으로 변환
})
.then(data => { //data에는 responese.json()의 결과가 들어감.
console.log('Success:', data);
})
.catch(error => {
console.error('Error:', error);
});
});
이렇게 Fetch API에 대해서도 알아보았다.
다음엔 jquery로 ajax통신하는 법을 알아보겠다.
'프로그래밍 언어 > JavaScript' 카테고리의 다른 글
[jQuery] 클라이언트와 서버간의 비동기통신에 대해 알아보자. / 3부 (0) | 2024.01.14 |
---|---|
[Javascript] 클라이언트와 서버간의 비동기통신에 대해 알아보자. / 1부 (0) | 2024.01.14 |