✅ promise의 필요성
👉 과거에 결과값을 반환받는 일반적인 방법 콜백을 사용했다. (비동기는 리턴으로 반환받을 수 없으므로)
비동기형식의 리턴은 무조건 콜백. 작업이 완료되는 시점은 무조건 콜백으로 해결했었다. (콜백의 콜백이 계속 이루어짐)
(* 비동기 아닌 것은 그냥 return쓰면됨)
👉 새로운 대안인 반환방법 ▶ promise 객체
👉 일단 비동기 진행을 하고, 결과가 성공했는지 실패했는지 여부에 따라 전달해주는 값이 달라진다. 콜백 (전화기)를 전달하는 주체가 직접 값을 받는게 아니라, promise에게 일단 전달하게 한다.

🔥 즉 프로미스의 역할은
- 프로미스를 사용하면 비동기 메서드에서 마치 동기메서드처럼 값을 반환할 수 있다 ▶ 콜백함수를 따로 쓰지않고도 리턴값이 왔을때 전달해 줄 수 있기 때문!
- 최종결과를 바로 주는게 아니라 promise 객체를 반환한다
- promise를 보면 상태값을 확인 가능하다
#️⃣ 콜백에서 전달되는 함수인자를 밖으로 빼내보기

👉 기존의 콜백형태는 함수가 실질적인 로직을 안보이게 하는 부정적 문제가 있음.

👉 함수와 Promise: JavaScript에서 함수는 일급 객체로 간주되며, 함수를 변수에 할당하거나 매개변수로 전달하고 반환할 수 있다. 따라서 Promise 내에서 함수를 사용하거나 반환할 수 있다.


//promise는 동기형도 가능하게 해준다
button.onclick = function (e) {
let promise = get(`http://localhost:8080/api/menus`); //promise 객체를 받는다
console.log(promise);
//promise는 리턴값을 받아놨다가 사용할곳에 연결함 then은 promise객체가 가진 서비스함수. function의 결과값을 넘긴다.
promise.then(function (response) {
console.log(response);
});
}

🔥 promise는 promise객체만 전달하는게 아니다! 여러번 사용하면 그 내부값도 뽑아낼 수 있다
🔥 즉 비동기는
- 나한테 바로 함수를 받게하거나
- promise객체한테 대신 전달해서 처리하게 한다.
#️⃣ html에서 promise를 제공하는 fetch를 사용해본다면?

👉 fetch api: 원격 데이터를 요청할 수 있게 하는 api.
Fetch API - Web API | MDN
Fetch API는 네트워크 통신을 포함한 리소스 취득을 위한 인터페이스를 제공하며, XMLHttpRequest보다 강력하고 유연한 대체제입니다.
developer.mozilla.org


👉 원래대로 내용을 읽고싶으면 readablestream을 사용하면 되긴하지만, 복잡하므로 그냥 반환된 response에다가 .json()을 하면 됨

👉 reponse.json()을 하면 JSON으로 인코딩된 데이터를 반환하기 위한 개체를 쉽게 만들 수 있다 반환되어 온 response객체를 .json()으로 파싱하면 됨

👉 즉 fetch사용시 json()은 response에서 json객체로 parsing하기 위한 메서드. 이때 비동기로 파싱됨!

#️⃣ (fetch()) promise를 중첩으로 꺼내기 싫다면, 리턴시켜서 다시 사용할 수 있다
- fetch api가 있으므로 굳이 함수를 만들어 쓸 필요가 없고 fetch를 쓰면 된다.
- fetch api가 반환하는것이 promise이므로 promise를 같이 알아야 할 필요가 있다는 것.
🔥 reponse 까는 절차 재정리
//fetch 사용해보기 ----------------
button.onclick = function (e) {
// --- promise를 지원하는 fetch함수.html5에 포함되어있다.
// 이 자체가 XHR을 대체한다. 위에서 직접 만든 get함수가 필요없어짐!
let promise = fetch(`http://localhost:8080/api/menus`);
console.log(promise); //promise객체(==fetch가 응답하는 response)
promise.then(response => {
// console.log(response.json()); //response -> json객체로 전환
return response.json();
//위에 console.log()를 살려두면 parsing한 json이 이미 스트림으로 읽혔다고 나오므로 죽여줘야함
})
.then(data => {
console.log(data); //우리가 원하는 배열 json이 나온다
})
//위의 첫번째 람다식은 이 표기법과 동일하다
// promise.then(function (response) {
// console.log(response);
// })
}
✅ fetch api 이용방법
#️⃣ 동기형으로 이용하기
//fecth 에 await와 async 사용해보기 ---------------------
button.onclick = async function (e) {
let response = await fetch(`http://localhost:8080/api/menus`); //promise로 값을 미리받지않고 기다렸다가 데이터를 받기 위해 사용
// console.log(response);
let jsonList = await response.json(); //json파싱도 비동기로 처리되므로 기다렸다가 받는다
console.log(jsonList);
}
#️⃣ 코드해설. fetch를 사용하여 비동기적으로 데이터를 가져오고, async/await를 사용하여 비동기적으로 데이터를 처리하는 방법. ✔️ async 함수 : 이벤트 핸들러 함수인 async function (e)는 async 키워드로 정의되어 있다. 이는 이 함수가 비동기 함수임을 나타내며, await 키워드를 사용할 수 있도록 한다. 👉 await를 사용하려면 함수가 비동기여야하는데 (비동기여야 기다려줄수있으니까!) 이때 기다려야 할 함수에 asnyc를 붙인다. ✔️ await fetch(...) : await 키워드는 비동기 작업의 완료를 기다린다. 여기서는 fetch 함수를 사용하여 웹 리소스를 가져오고, 이 리소스를 response 변수에 할당한다. await를 사용하면 fetch 작업이 완료될 때까지 다음 코드가 실행되지 않는다. 👉 (* 즉 XHR방식에서 데이터가 와야지 onload가 실행되는것과 비슷하며 await는 비동기적으로 실행되는 함수가 동기적으로 실행되는것 처럼 보이게 만들어서 작업을 직관적으로 보이게 한다) ---------- 여기서 나는 비동기작업을 하고있는데 await로 기다리게 함으로써 작업을 동기적으로 바꾸는건가??하고 혼선이 왔었음!!! ✔️ await response.json() : 다음으로 response.json()을 사용하여 response 객체에서 JSON 데이터를 추출한다. 이 또한 await를 사용하여 비동기적으로 처리되며, JSON 데이터가 완전히 파싱될 때까지 대기한다. ✔️ 데이터 출력 : 파싱된 JSON 데이터는 jsonList 변수에 저장되고, 이 데이터를 console.log를 사용하여 출력한다. 이러한 구조는 비동기 작업을 보다 간단하게 처리하고 가독성을 높일 수 있으며, 코드의 순서와 실행을 더 명확하게 표현할 수 있다. |
👉 promise를 먼저 받지 말고 sync, await기능으로 json()이 완료된 결과를 받는다
#️⃣ await를 통해 response.json() 객체를 받을때와 promise를 생성해서 resolve로 받을때를 비교하기


//fecth 에 await와 async 사용해보기 ---------------------
button.onclick = async function (e) {
let response = await fetch(`http://localhost:8080/api/menus`); //promise로 값을 미리받지않고 기다렸다가 데이터를 받기 위해 사용
// console.log(response);
let jsonList = await response.json(); //json파싱도 비동기로 처리되므로 기다렸다가 받는다
console.log(jsonList); //파싱이 완료된 json배열이 나온다 (9)[{...},{...},...]
console.log(jsonList[0].korName); //이렇게 하면 값에 바로 접근가능하다
//----- response와 별도로 promise 객체생성
let promise = new Promise(resolve => {
resolve(jsonList); //fetch의 결과로 resolve에 jsonList가 담긴다
})
// console.log(promise); //promise 객체 안에 json배열이 들어있다
//then을 통해 promise객체에서 json이 뽑혀나온다
promise.then(data => console.log(data));//(9)[{...},{...},...]
//promise객체에서 세부 내역으로 접근하기 -- 접근할땐 위에서 console로 뽑은걸 죽이고 접근해야한다. 스트림이 끊기지않게!
// promise.then(list => list[0])
// .then(menu => menu.korName)
// .then(korName => korName.length)
// .then(length => console.log(length))
}
👉 awiat는 기다렸다가 응답바디를 받아서 응답바디를 다시 json()파싱하는걸 기다렸다가 받으면 바로 결과(배열json)를 볼 수 있다. (바로 배열의 키에 접근할 수 있다)
👉 반면 promise로 받게되면 resolve 내부에 json배열이 담겨있기 때문에 .then을 통해서 한번 파싱을 해주어야 결과 (배열 json)을 볼 수 있다. 파싱을 해준 후에 promise의 메서드인 .then을 가지고 내부로 들어갈 수 있다.
** 지역화를 벗어날땐 (==지역변수를 선언할 일이 없거나 내부에서 처리할 일이 없을땐) 람다식을 써주는게 좋다
✅ 기존 XMLHttpRequest를 FETCH 방식으로 바꾸기
categoryUl.onclick = async function(e) { //async를 하면 내부에서 지역변수가 가능하다. 비동기일경우 각자의 값이 다른줄로 가기때문
e.preventDefault(); // 기본 작동값을 막는다
//e.target도 연산이므로 지역변수를 선언해줌
let el = e.target;
// a태그가 아니면 이벤트를 발생시키지않고 리턴시킨다
// 엘리먼트가 아니고 이벤트객체이므로 e.target.tagname이라고 해야함 (그냥 e.tagname이 아님)
if (el.tagName != "A")
return;
let response;
if (el.dataset.id == 0) {
response = await fetch(`/api/menus`);
} else {
response = await fetch(`/api/menus?c=${el.dataset.id}`);
}
let json = await response.json(); //response를 json으로 바꾼다
/*console.log(json);
console.log(typeof(json)); //object로 출력된다*/
bind(json);
//el.className+=" current"; //기존 클래스명에 추가해야 하므로 +=연산자에 문자열도 띄어쓰기해준다
// classList 클래스이름을 빈공백으로 구분해서 관리함
currentCategory.classList.remove("current");
el.classList.add("current");
currentCategory = el;
#️⃣ 만약 json이 아닌 text로 바로 꺼내고싶다면?
let response;
if (el.dataset.id == 0) {
response = await fetch(`/api/menus`);
} else {
response = await fetch(`/api/menus?c=${el.dataset.id}`);
}
let text = await response.text();
console.log(typeof(text)); //string이 반환된다

👉 이렇게 text로 온걸 json형태로 쓰고싶다면 다시 text.json()을 해줘야 한다.(string에서 json 타입화) 번거로우므로 바디에 담긴 text그대로 쓸 떄만 사용하고, json으로 쓸 데이터가 온다면 애초부터 json()으로 불러서 쓰도록 하자.
✅ CSR로 like 버튼 클릭처리
반복문으로 문서가 구성되어 있기 때문에, 좋아요 아이콘이 몇개가 있을지 모른다. 그래서 btn-like로 아이콘에 달아놨지만 부모객체에서 like를 확인해야 한다.
content.onclick = (e) => {
e.preventDefault();
let el = e.target;
if (!el.classList.contains("btn-like")) //btn-like를 가지고 있지 않을 경우 return
return;
if (el.classList.contains("btn-like"))
console.log("하트");
}
'😵 ~23.11.10' 카테고리의 다른 글
1017 | 인증과 권한 개념, 세션과 쿠키 (0) | 2023.10.17 |
---|---|
1017 | rest와 restful , api url짜기 (1) | 2023.10.17 |
1013 | 전체메뉴 조회, bind로 중복화면 묶어주기, promise 개념, CORS개념, 콜백함수 개념 (0) | 2023.10.13 |
1012 | 카테고리에 db반영, 전체박스 온클릭 이벤트와 자손 타겟 구별하기, 타겟에 클래스속성 부여하기(element.classList), 클릭값만 api로 데이터받기 (0) | 2023.10.12 |
1011 | dbms trigger개념, 좋아요 클릭여부 컬럼만들기, 좋아요 아이콘 변경(클래스 갈아끼기), 서버에서 이미지 불러오기 , 최종 CSR 렌더링 (0) | 2023.10.11 |