- 비동기 ajax, fetch, axios, async/await, promise2024년 10월 29일
- chantleman
- 작성자
- 2024.10.29.:59
https://chantleman.tistory.com/entry/XMLHttpRequest
https://chantleman.tistory.com/entry/fetch
https://chantleman.tistory.com/entry/async-await
SPA (Single Page Application)는 말그대로 하나의 페이지를 사용하는 애플리케이션을 뜻함
새로운 페이지로 이동하는 것이 아닌, 하나의 페이지에서 내용을 동적으로 변경함
대표적인 방식으로 AJAX가 있음
원본 ajax
기본 코드
let xhr = new XMLHttpRequest(); xhr.open(method, url, 비동기여부); xhr.send(); //get이 아닐때만 내용 담기
function ajax() { let xhr = new XMLHttpRequest(); xhr.open("get", "/ajax/data.csv", true); //false로 하면 동기 xhr.onreadystatechange = function () { if (xhr.readyState == 4 && xhr.status == 200) { console.log(xhr.responseText); alert("두번째 출력"); } } xhr.send(); } ajax(); alert("첫번째 출력");
alert("첫번째 출력") 가 ajax()함수보다 빨리 실행됨 ← 비동기 (앞코드보다 뒷코드가 더 빨리 실행)
xhr.open()에서 비동기여부를 false로 하면 ajax()함수가 먼저 실행되고 그 다음에 alert ("첫번째 출력")가 뜸
비동기 결과 처리 함수를 따로 정의해서 사용
function ajax() { let xhr = new XMLHttpRequest(); xhr.open("get", "data.html", true); xhr.onload = function() { if (xhr.status == 200) { process(xhr.responseText); } }; xhr.send(); } function process(Rslt){ console.log("결과: ", Rslt); }
onload 이벤트 핸들러를 사용하면 xhr.readyState를 직접 체크할 필요없음
아래처럼 함수호출할 때 매개변수를 넣어 보낼수도 있음
function ajax(method, url, cbfnc){ let xhr = new XMLHttpRequest(); xhr.open(method,url,true); xhr.onreadystatechange = function(){ if(xhr.status==200 && xhr.readyState==4){ cbfnc(xhr.responseText); } } xhr.send(); } ajax("get","data.html",(fnc)=>{ console.log("html 파일: ",fnc); }); ajax("get","data.csv",function(fnc2){ console.log("csv 파일: ", fnc2); });
매개변수를 한개로
즉, 속성을 가진 덩어리 객체로 보낼수도 있음
opt={ method:"get", url:"data.json", async: true, dataType:"json", cbfnc: function(arg){ console.log("체킁",arg);} } function ajax(arg){ let xhr = new XMLHttpRequest(); xhr.open(arg.method,arg.url,arg.async); xhr.onreadystatechange = function(){ if(xhr.status==200 && xhr.readyState==4){ if(arg.dataType=="json"){ arg.cbfnc(JSON.parse(xhr.responseText)); }else{ arg.cbfnc(xhr.responseText); //텍스트 형식으로 보냄 } } } xhr.send(); } ajax(opt);
jquery ajax
$.ajax(...)
위 코드를 변형하면 jQuery ajax가 됨
네임스페이스로 사용할 수 있는 기호에는 _(언더바)와 $가 있음
그 중 $를 사용하여 빈 객체를 생성 후
거기에 보낼 매개변수를 담아 함수를 호출하면 jquery ajax 방식과 동일함
const $={}; //빈 객체 생성 $.ajax = function(opt){ let xhr = new XMLHttpRequest(); xhr.open(opt.method,opt.url,opt.async); xhr.onreadystatechange = function(){ if(xhr.status==200 && xhr.readyState==4){ if(opt.dataType=="json"){ opt.cbfnc(JSON.parse(xhr.responseText)); }else{ opt.cbfnc(xhr.responseText); } } } xhr.send(); } $.ajax({ method:"get", url:"data.html", async:true, //dataType:"json", //html(data.html)은 json으로 parse할 수 없음 dataType:"text", cbfnc:function(rslt){ console.log("체킁",rslt); } });
서버에서 문자열을 보내면 스크립트에서 json으로 parse해줌 (서버에서 parse하는 것이 아님 !)
<!DOCTYPE html> <meta charset='UTF-8'> <div id="disp"></div> <script> const disp = document.querySelector("#disp"); const $ = {}; //빈객체 생성 $.ajax = function (opt) { let xhr = new XMLHttpRequest(); xhr.open(opt.method, opt.url, opt.async); xhr.onreadystatechange = function () { if (xhr.status == 200 && xhr.readyState == 4) { try { opt.cbfnc(JSON.parse(xhr.responseText)); } catch (error) { opt.cbfnc(xhr.responseText); } } } xhr.send(); } $.ajax({ method: "get", url: "data.json", async: true, cbfnc: function (rslt) { console.log("체킁", rslt); for (let i = 0; i < rslt.length; i++) { disp.innerHTML += `${rslt[i].name}는 ${rslt[i].age}살 ${rslt[i].alias}로 불림 <br>`; } } }); </script>
이렇게 dataType을 직접 지정해주지 않고, try-catch문으로 처리해줄 수도 있당
promise
미래에 실행됨
hell of callback(무한 콜백)때문에 코드 가독성이 떨어짐
promise 문법이 도입되면서 비동기를 깔끔하게 해줌
resolve - 잘 이행됐을때
reject - 에러났을때
pending - 대기
.then() 으로 resolve 처리
.catch()로 reject 처리
.finally는 항상
finally는 클라이언트 사이드 프로그램에서는 거의 안쓰이고,
서버 사이트 프로그램이라면 로그 저장 등에 활용할 수 있음
function mgMukbang(){ return new Promise((res, rej)=>{ res("성공"); //성공 시에 부르는 함수 resolve //rej("에러!!"); //실패 시에 부르는 함수 reject }) } mgMukbang().then(pArg=>{ console.log("잘됐닝? ", pArg); //resolve }).catch(pErr =>{ console.log("잘됐닝? ", pErr); //reject }).finally(()=>{ console.log("전 그냥 항상 불려용"); //항상 });
fetch
fetch API는 결국 XMLHttpRequest AJAX인데 promise를 리턴하도록 만들어준 API임
그래서 .then()을 쓸 수 있음
fetch("data.json").then(res=>{ console.log(res); })
이렇게 바로 결과 안 주고, response 객체를 보여줌
response의 내용물을 보려면 text()나 json()을 붙여야하는데 그것마저도 promise 객체를 리턴해서 .then()을 붙여야함
fetch("data.json").then(res=>{ res.text().then(result=>{ console.log("text 체킁", result); }); })
fetch("data.json").then(res=>{ res.json().then(result=>{ //JSON.parse()한 결과를 줌 console.log("json 체킁", result); }); })
data.json 파일이 배열로 돼있지만
text()로 하면 텍스트 형태로 나오고, json()으로 하면 배열 형태로 잘 나온 것을 알 수 있음
하지만!
axios는 json.parse도 알아서 해준당
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/1.7.7/axios.min.js" ></script>
axios.get("data.json").then(res=>{ console.log("체킁22", res.data); })
axios는 클라이언트/서버 양쪽에서 모두 사용 가능(단, 서버가 node.js일 경우에만 ! )
java로 할 때는 클라이언트만 axios 사용 가능
axios의 web socket으로 알림 기능을 구현할 수 있음
원래는 클라이언트 → 서버로 요청해야지만 response를 할 수 있는데
실시간 알림 기능을 구현하려면 1초마다 request해야되는데 그러면 서버 공격이잔항?
그럴때 websocket을 사용하는데, websocket을 사용하면 연결을 유지한 상태에서 양방향 통신이 가능해진당.
참고로 HTTP는 클라이언트의 요청이 있고, 그 다음 서버로부터 응답을 받아야한당 (단방향)
클라이언트에서 요청할때 AJAX의 XMLHttpRequest객체가 생성되고, 그 객체가 서버와의 연결을 잡아둔당
한번 클라이언트의 요청에 의해 연결이 되면 그 결과로 연결된 소켓의 정보를 가진 객체가 생기는데, 그 객체로 요청없이 응답을 받아 실시간 통신이 가능해진당!!
이를 활용한 대표적인 기능이 바로 푸시 알림 기능이당
서버와 클라이언트는 항상 연결상태를 유지하므로 서버가 알림을 보내고싶을 때 클라이언트로 직접 푸시할 수 있당
axios
아까 원본 ajax를 jquery ajax로 변형한 것처럼
const axios={}; //빈 객체 생성 axios.get = function ajxPro(url) { return new Promise((res, rej) => { let xhr = new XMLHttpRequest(); xhr.open("get", url, true); xhr.onreadystatechange = function () { if (xhr.status == 200 && xhr.readyState == 4) { res(xhr.responseText); } } xhr.send(); }) }
이렇게 하면 axios 방식과 동일함
axios.get("data.json").then((rst)=>{ console.log("성공",rst); }).catch(err=>{ console.log("에렁", err); });
then/catch만 잘 쓰면 끝날 줄 알았지만 !! 콜백지옥이랑 다를게 없음
그래서 나온것이 async / await
async / await의 단점은 문법상 꼭 함수를 만들어야한다는 것
그래서 단순한 건 then 사용!
async / await
async function asc(){ alert("첫번째 실행"); let rslt = await axios.get("data.json"); console.log("체킁",JSON.parse(rslt)); alert("세번째 실행"); } asc(); alert("두번째 실행");
awiat뒤에는 무조건 promise를 리턴하는 게 와야하기 때문에 await에는 비동기함수가 들어감
await 뒤에 있는 애들은 잠깐 기다려! 다른 애들 먼저 실행하게.
근데 기다리는 건 비동기가 아닌데 왜 이게 비동기방식??
의도적으로 "두번째 실행 "먼저 하고 그다음에 "세번째 실행"을 실행시키기 위해
비동기지만 동기처럼 사용할 수 있음
728x90'js' 카테고리의 다른 글
모달 (0) 2024.11.04 json parse (2) 2024.10.31 localStorage (0) 2024.10.23 Configure Snippets. 템플릿 (0) 2024.10.23 볼튕기기 (1) 2024.10.17 다음글이전글이전 글이 없습니다.댓글