[JS]Ajax와 비동기 처리

블랑·2023년 3월 16일
0

[FE] - HTML/CSS/JavaScript

목록 보기
14/14

사전 요약 :
1. 전체 페이지 갱신이 아닌 '비동기적'으로 처리하고 싶다 = Ajax를 사용하겠다.
2. 해당 기능을 구현하기 위해 XMLHttpRequest() 객체를 선언하고 이를 이용한다.
3. 하지만 XMLHttpRequest() 객체를 선언하고 반복되는 작업을 효율적으로 바꾸겠다 = fetch 사용
4. fetch의 반환값은 Promise이고, promise는 비동기 처리를 수행한다. 콜백함수를 사용할 수도 있지만, 가독성과 유지보수성이 용이하기 때문에 promise를 사용한다.

AJAX 소개

AJAX : Asynchronous JavaScript and XML의 약자로, 비동기적으로 서버와 브라우저가 데이터를 교환하는 기술

데이터가 바뀔 경우 새로고침(F5) 해야 웹 사이트가 바뀌는데 이를 바로 수정해준다.
다만 DOM 형식이기에 개발자가 귀찮아졌을 뿐이다.

  1. Ajax는 언어나 프레임워크가 아닌 구현하는 방식을 의미한다.
  2. 웹에서 화면을 갱신하지 않고 데이터를 서버로부터 가져와 처리하는 방법을 의미한다.
  3. JavaScript의 XMLHttpRequest(XHR) 객체로 데이터를 전달하고 비동기 방식으로 결과를 조회한다.
  4. 화면 갱신이 없기에 사용자 입장에서는 상당히 편리하지만, 동적으로 DOM을 구성해야 하므로 구현이 복잡하다.

일반 요청 vs Ajax요청

일반 요청에 대한 응답

  • data를 입력 후 이벤트 발생
  • Ajax를 적용하지 않은 요청은 서버에서 data를 이용하여 logic 처리
  • logic 처리에 따라 응답 페이지를 생성 후 클라이언트에 전송(화면전환)

Ajax 요청에 대한 응답

  • data를 입력 후 event 발생
  • Ajax를 적용하면 event 발생 시 서버에서 요청을 처리한 후 Text, XML 또는 JSON으로 응답
  • 클라이언트(Browser)에서는 응답 데이터를 기반으로 화면 전환 없이 현재 페이지에서 동적으로 화면을 재구성

GET과 POST

이전에 학습하였던 http 전송 방식 중 두 가지를 다시 비교해보자.

GET

  • url에 변수(데이터)를 포함시켜 요청한다.
  • 데이터를 헤더에 포함하여 전송한다.
  • url에 데이터가 노출되어 보안에 취약하다.
  • 전송하는 길이에 제한이 있다.
  • 캐싱 가능

POST

  • url에 변수(데이터)를 노출하지 않는다.
  • 데이터를 바디에 포함하여 전송한다.
  • url에 데이터가 노출되지 않아 기본 보안 가능
  • 전송하는 길이에 제한이 없다.
  • 캐싱 불가

실습 준비

Tomcat Application 서버를 열어서 실습을 진행해보자. tomcat 9.0 버전으로 사용해보겠다.

https://tomcat.apache.org/download-90.cgi

  1. 먼저 기본 Perspective 상태를 JAVA EE로 변경해주자.

  2. Dynamic Web Project로 새로운 프로젝트를 설정한다.

  3. new runtime - 다운받은 톰캣 9.0버전 적용 및 경로 선택

  4. next

  5. WebContent에 파일 가져오기

  6. maven 설정 적용

https://mvnrepository.com/artifact/com.googlecode.json-simple/json-simple/1.1.1

maven 링크 복사 후 붙여넣기(pom.xml)

  1. 크롬으로 설정

XMLHttpRequest (수정필요)

XMLHttpReqyest는 자바스크립트가 Ajax 방식으로 통신할 때 사용되는 객체이다.

비동기로 작동하며 Promise를 반환한다. 기본적으로 GET 메소드를 사용한다.

fetch()

브라우저에서 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, 두 번째 인자로 option 객체를 받는다.
fetch(url, options);
  • options에 아무것도 넘기지 않으면 요청은 GET 방식으로 진행되며, url로부터 contents가 다운로드 된다.
  • 실행 결과 Promise 타입의 객체를 반환한다.
  • 반환된 Promise 객체는 API 호출이 성공했을 경우 응답 객체(response)를 resolve하고, 실패했을 경우 예외(error) 객체를 reject한다.
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

Promise()와 비동기 처리

개념

fetch() 함수의 반환 값.
프로미스를 사용하는 이유는 비동기 처리를 효율적으로 관리하기 위해서이다.

비동기 처리(Asynchronous processing)란, 어떤 작업이 실행되는 동안에도 다른 작업을 동시에 처리할 수 있는 방식을 의미한다.

즉, 작업을 순차적으로 처리하지 않고 병렬적으로 처리하여 처리 시간을 줄이고 성능을 향상시키는 방법이다.

일반적으로 JavaScript에서 비동기 처리는 콜백 함수나 프로미스 등을 이용하여 구현하게 된다.

비동기 처리를 위해 콜백 함수를 중첩해서 사용하면 Callback Hell 문제가 발생할 수 있기에, 함수의 실행 순서와 종료 시점을 파악하기 어렵고, 디버깅과 에러 처리도 어려워진다.

상태와 사용 이유

프로미스는 총 세 가지 상태를 가질 수 있다.

대기 중(Pending) : 비동기 처리가 아직 수행되지 않은 초기 상태.
이행됨(Fulfilled) : 비동기 처리가 성공적으로 완료된 상태.
거부됨(Rejected) : 비동기 처리가 실패한 상태.

사용 이유

    1. 비동기 처리를 보다 간편하게 관리할 수 있다.
      콜백 함수를 사용하여 비동기 처리를 구현하는 방법은 코드가 복잡해지고 유지보수가 어렵다.
      프로미스를 사용하면 비동기 처리를 보다 간단하게 처리할 수 있습니다.
    1. 가독성이 좋아진다.
      프로미스는 비동기 처리 코드를 동기적으로 작성할 수 있게 한다.
      이렇게 하면 코드의 가독성이 좋아지며, 디버깅이나 유지보수도 보다 쉬워진다.
    1. 에러 처리가 간편하다.
      프로미스는 거부 상태일 때 에러 처리를 쉽게 할 수 있다.
      콜백 함수를 사용하여 에러 처리를 구현하는 방법은 코드가 복잡해지고 가독성이 나쁘기에 프로미스가 등장하였다.

종합 정리 예시코드

    <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>

실행 결과 :

profile
안녕하세요.

0개의 댓글