사전 요약 :
1. 전체 페이지 갱신이 아닌 '비동기적'으로 처리하고 싶다 = Ajax를 사용하겠다.
2. 해당 기능을 구현하기 위해 XMLHttpRequest() 객체를 선언하고 이를 이용한다.
3. 하지만 XMLHttpRequest() 객체를 선언하고 반복되는 작업을 효율적으로 바꾸겠다 = fetch 사용
4. fetch의 반환값은 Promise이고, promise는 비동기 처리를 수행한다. 콜백함수를 사용할 수도 있지만, 가독성과 유지보수성이 용이하기 때문에 promise를 사용한다.
데이터가 바뀔 경우 새로고침(F5) 해야 웹 사이트가 바뀌는데 이를 바로 수정해준다.
다만 DOM 형식이기에 개발자가 귀찮아졌을 뿐이다.
이전에 학습하였던 http 전송 방식 중 두 가지를 다시 비교해보자.
Tomcat Application 서버를 열어서 실습을 진행해보자. tomcat 9.0 버전으로 사용해보겠다.
https://tomcat.apache.org/download-90.cgi
먼저 기본 Perspective 상태를 JAVA EE로 변경해주자.
Dynamic Web Project로 새로운 프로젝트를 설정한다.
new runtime - 다운받은 톰캣 9.0버전 적용 및 경로 선택
next
WebContent에 파일 가져오기
maven 설정 적용
https://mvnrepository.com/artifact/com.googlecode.json-simple/json-simple/1.1.1
maven 링크 복사 후 붙여넣기(pom.xml)
XMLHttpReqyest는 자바스크립트가 Ajax 방식으로 통신할 때 사용되는 객체이다.
비동기로 작동하며 Promise를 반환한다. 기본적으로 GET 메소드를 사용한다.
브라우저에서 fetch() 함수를 지원하기 전에는 XMLHttpRequest를 이용하여 직접 HTTP를 요청하고 응답을 직접 구현했다.
너무나도 복잡했기 때문에 jQuery와 axios와 같은 라이브러리를 사용하곤 했다.
또한 XMLHttpRequest() 객체 대신 fetch API를 사용하면 더 많은 기능을 지원하고, 더욱 간편하게 사용할 수 있게 된다.
<script type="text/javascript">
let xhr = new XMLHttpRequest(); //객체 생성
xhr.onreadystatechange = function() { //처리를 위한 콜백 함수,
/*
onreadystatechange는 XMLHttpRequest 객체에서 상태 변화가 생겼을 때 호출되는 이벤트 핸들러이다.
이 속성에 할당한 함수는 readyState 속성 값이 변할 때마다 호출되며, XMLHttpRequest 객체의 상태 변화에 따라 다양한 처리를 할 수 있다.
statechange : 상태가 바뀔 때
준비가 됐을 떄의 상태 (0-> 1) 보낼 준비가 됐을때(2 -> 3).. 등 상태는 0~4번이 있다.
해당 함수가 호출 되면 총 상태가 4번 바뀐다.
0: 초기화되지 않은 상태
1: 연결이 설정된 상태
2: 요청이 받아들여진 상태
3: 요청 처리 중인 상태
4: 요청 처리가 완료된 상태
*/
if (xhr.readyState === 4 && xhr.status == 200) { //데이터가 다 왔으면 처리 && 응답코드가 올바를 때
// xhr.responseText // 응답결과
} else { //아직 데이터가 안 왔을 때
// 처리 중 이미지...
}
};
/*
.open() 메소드는 XMLHttpRequest 객체가 어떤 방식으로 서버와 통신할 것인지를 설정하는 메소드.
즉, 이 메소드를 통해 서버로 어떤 요청을 보낼 것인지와 요청 방식, 요청 URL을 설정할 수 있다.
xhr.open("요청방식(GET, POST, PUT, DELETE, PATCH)", "URL?QueryString", "동기/비동기여부"); //어차피 Ajax는 비동기 통신을 쓰기 위함이 주 목적
*/
xhr.open("GET", "/idcheck?id=a"); //생성자 생략 시 비동기 default
xhr.send("id=a"); //POST 방식일 경우 추가정보를 send에 붙여서 호출
/* ========= 지금까지의 내용을 fetch()로 함축할 수 있다! 매번 쓰기 귀찮기 때문. */
</script>
fetch(url, options);
fetch(url, options)
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));
자세한 개념은 아래 Promise를 참조할 것.
(Fetch 사용하기)
https://developer.mozilla.org/ko/docs/Web/API/Fetch_API/Using_Fetch
fetch() 함수의 반환 값.
프로미스를 사용하는 이유는 비동기 처리를 효율적으로 관리하기 위해서이다.
비동기 처리(Asynchronous processing)란, 어떤 작업이 실행되는 동안에도 다른 작업을 동시에 처리할 수 있는 방식을 의미한다.
즉, 작업을 순차적으로 처리하지 않고 병렬적으로 처리하여 처리 시간을 줄이고 성능을 향상시키는 방법이다.
일반적으로 JavaScript에서 비동기 처리는 콜백 함수나 프로미스 등을 이용하여 구현하게 된다.
비동기 처리를 위해 콜백 함수를 중첩해서 사용하면 Callback Hell 문제가 발생할 수 있기에, 함수의 실행 순서와 종료 시점을 파악하기 어렵고, 디버깅과 에러 처리도 어려워진다.
프로미스는 총 세 가지 상태를 가질 수 있다.
대기 중(Pending) : 비동기 처리가 아직 수행되지 않은 초기 상태.
이행됨(Fulfilled) : 비동기 처리가 성공적으로 완료된 상태.
거부됨(Rejected) : 비동기 처리가 실패한 상태.
<script>
//console.dir(fetch);
//console.dir(fetch('member.txt')); //open, send 등 모든 코드 생략 가능 , Promise 반환
//let p = fetch('member.txt'); //promise 객체 반환
// axios // Promise 객체 반환
// Promise 객체는 ES6부터 지원되었다.
// 비동기 연산이 종료된 이후의 결과값이나, 실패 이유를 처리하기 위해서 연결하는 방법을 지원한다.
// Promise를 이용하면 비동기 메서드에서 동기 메서드처럼 값을 반환할 수 있다.
// executor : 콜백 함수 지정(resolve, reject)
//
// resolve 함수를 호출하면 then 실행
// reject 함수를 호출하면 catch 실행
const p = new Promise(function (resolve, reject) {
//성공 시엔 resolve 함수 실행
//실패 시엔 reject 함수 실행
console.log('executor 실행'); //이 코드 안에서는 비동기 코드가 주로 쓰여짐 : Promise는 비동기 처리를 위해 만들어진 객체이기에
//resolve(); //state 4 && status 200
reject();
});
console.log("동기 코드 A");
//p 객체 내의 코드가 비동기 코드였을 경우 A 코드가 먼저 실행될 수 있다.
//p.then(); -> p 내의 resolve(성공)이 호출되었을 경우 then()이 실행
//.catch(); -> 반대로 실패일 경우 catch가 실행.
p.then(function () {
console.log('성공하였음');
}).catch(function () {
console.log('실패하였음');
});
</script>
실행 결과 :