✅ promise의 필요성

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

 

🔥 즉 프로미스의 역할은

  1. 프로미스를 사용하면 비동기 메서드에서 마치 동기메서드처럼 값을 반환할 수 있다  ▶ 콜백함수를 따로 쓰지않고도 리턴값이 왔을때 전달해 줄 수 있기 때문!
  2. 최종결과를 바로 주는게 아니라 promise 객체를 반환한다
  3. promise를 보면 상태값을 확인 가능하다

 
 
 
 

#️⃣ 콜백에서 전달되는 함수인자를 밖으로 빼내보기

콜백에서 함수를 밖으로 빼서 정리

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

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

객체에 string을 더하면 json이 객체화 돼서 object로 나오기 때문에 console.log에 저렇게 더해주면 안됨 ***
//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객체만 전달하는게 아니다! 여러번 사용하면 그 내부값도 뽑아낼 수 있다

    // --우리가 만든 get함수
        let promise = get(`http://localhost:8080/api/menus`); //promise 객체를 받는다
        console.log(promise); //promise 객체 반환 (pending)

        //promise가 가진 서비스함수 then을 가지고 promise 객체의 값을 뽑아낼 수 있다.
        promise
            .then(function (response) { //then내에서 json데이터를 파싱하여 반환한다
                console.log(response); //[json형태]
                return response;
            })
            .then(function (jsonlist) {
                console.log(jsonlist[0]); //json 중 0번째 를 뽑는다
                return jsonlist[0]; //원하는 json 한줄 추출 -- {id:331, korName:'사약스무디'...}
            })
            // .then(function (menu0) {
            //     console.log(menu0.korName); //-- 이렇게 하면 0번째 배열의 korName을 뽑을수있다
            // })
            .then(function (menu) {  //-- 0번째 json객체 하나가 나온다
                console.log(menu);
            })

 
 
🔥 즉 비동기는

  1. 나한테 바로 함수를 받게하거나
  2. promise객체한테 대신 전달해서 처리하게 한다. 

 


 

#️⃣ html에서 promise를 제공하는 fetch를 사용해본다면?

    //fetch 사용해보기 ----------------
    button.onclick = function (e) {
        // --- promise를 지원하는 fetch함수.html5에 포함되어있다.
        // 이 자체가 XHR을 대체한다. 위에서 직접 만든 get함수가 필요없어짐!
        let promise = fetch(`http://localhost:8080/api/menus`);
        console.log(promise);

        promise.then(response => {
            console.log(response);
        })

        //위의 람다식은 이 표기법과 동일하다
        // promise.then(function (response) {
        //     console.log(response);
        // })
    }

👉 fetch api: 원격 데이터를 요청할 수 있게 하는 api.
 

Fetch API - Web API | MDN

Fetch API는 네트워크 통신을 포함한 리소스 취득을 위한 인터페이스를 제공하며, XMLHttpRequest보다 강력하고 유연한 대체제입니다.

developer.mozilla.org

리소스 경로를 받아서 response로 이행하는 promise를 반환한다!

 

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

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

    //promise는 동기형도 가능하게 해준다
    button.onclick = function (e) {
        // promise를 지원하는 fetch함수. html5에 포함되어있다.
        let promise = fetch(`http://localhost:8080/api/menus`);
        console.log(promise);

        //--우리가 만든 get함수
        // let promise = get(`http://localhost:8080/api/menus`); //promise 객체를 받는다
        // console.log(promise);

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

        //promise는 리턴값을 받아놨다가 사용할곳에 연결함 then은 promise객체가 가진 서비스함수. function의 결과값을 넘긴다.
        promise
            .then(function (response) {
                let promise1 = response.json();

                promise1
                    .then(function (data) {
                        console.log(data);
                    })
            });
    }

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

fetch를 가지고 결과를 냄!!

 
 
 

#️⃣ (fetch()) promise를 중첩으로 꺼내기 싫다면, 리턴시켜서 다시 사용할 수 있다

 
    button.onclick = function (e) {
        // promise를 지원하는 fetch함수. html5에 포함되어있다.
        let promise = fetch(`http://localhost:8080/api/menus`);
        console.log(promise);
 
        //promise는 리턴값을 받아놨다가 사용할곳에 연결함 then은 promise객체가 가진 서비스함수. function의 결과값을 넘긴다.
        promise
            .then(function (response) {
                // let promise1 = response.json();
                return response.json(); //여기서 그냥 리턴시킴.

                //중첩으로 사용하는 방식
                // promise1
                //     .then(function (data) {
                //         console.log(data);
                //     })
            })
            .then(function (data) { // 중첩하지않고 리턴된 promise객체를 이어서 사용한다
                console.log(data);
            });
    }

 

  • 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("하트");
}

 
 
 
 
 
 

+ Recent posts