[TIL 0421] Callback과 비동기 처리

zitto·2023년 4월 21일
0

TIL

목록 보기
60/77
post-thumbnail

✔️ Callback 함수란

함수의 인자로 들어가는 함수


callback 함수를 왜 사용하는 걸까?

실행권한을 넘기기 위해!
끝나면 내거 보내줄테니 이거 실행시켜줘!


✔️ 비동기 실습( callback-> promise-> async/await)

1️⃣ CallBack

[실습 section 29-02]

`http://numbersapi.com/random?min=1&max=200` => 1부터 200사이의 랜덤숫자 가져오기
`https://koreanjson.com/posts/${num}` => 2.랜덤번째 게시글 조회하기
`https://koreanjson.com/posts?userId=${userId}`  => 해당작성자의 모든 게시글 조회하기
<!DOCTYPE html>
<html lang="ko">
  <head>
    <title>CallBackPromiseAsyncAwait</title>
    <script>
      function addEventListener(aaa, bbb) {
        // 아래 콜백함수(인자)를 받는 매개변수임!
        // setting된 API주소로 요청!
        const res = 70; // 셋팅된 API주로소부터 받아온 결과
        if (aaa === "load") {
          bbb(res); // 결과값을 넣어서 실행! 아래 콜백을 통해 위의 bbb매개변수로 받아 다시 지금의 bbb로 전달됨(함수실행부분)
        }
      }
      const myCallback = () => {
        const aa = new XMLHttpRequest();
        aa.open("get", `http://numbersapi.com/random?min=1&max=200`);
        //  const result = await aa.send(); //요청
        aa.send();
        aa.addEventListener("load", (res) => {}); // await없던 때 콜백함수보내서 실행시켜주기(함수선언부분)
        console.log(res); // API 요청 결과 잘 받아지는지 확인
        const num = res.target.response.split(" ")[0]; //랜덤숫자를 가져옴.
      };
      const myPromise = () => {};
      const myAsyncAwait = () => {};
    </script>
  </head>
  <body>
    <button onclick="myCallback()">CALLBACK</button>
  </body>
</html>
  • XMLHttpRequest 란?
    XMLHttpRequest는 서버와 상호 작용하기 위해 사용되는 객체로,
    전체 페이지의 새로고침 없이도 URL로부터 데이터를 받아올 수 있다.
    주로 Ajax 프로그래밍에 사용되며, XHR이라고 부름

필요한 데이터는 target 안에 들어있다.
문자열이므로 객체로 변환해서 뽑아와야 함.(JSON.parse)

❗️ 문제점

콜백안에 콜백이 들어가는 콜백지옥 현상이 발생함!


2️⃣ Promise

Promise객체를 활용한 라이브러리들이 많이 나옴
대표적인게 axios!!
데이터 통신에 사용되는 현대 라이브러리들은 대부분 Promise를 기반으로 만들어져 있다.

이말은 즉슨
리턴하는게 Promise객체라는 것!
axios를 통해 .then.catch.get을 사용할 수 있음

이것도 콜백지옥맞음!
콜백지옥을 제거하기 위해 return을 사용함!

axios의 리턴값이 프로미스!
이기능을 사용해 콜백지옥을 방지함!
-> promise chaining (각 요청들이 체인처럼 연결됨)

❗️문제점 1

실행순서를 예측하기 어려움!(직관적이지 않음)
예측하자면?

▼ 결과
axios 다운로드 받아서 확인하기!
sciprt형태로 가져오는 것 cdn방식
https://axios-http.com/kr/docs/intro

axios를 이용한 비동기 작업이 TaskQueue 안에 들어가, 실행 순서가 뒤로 밀렸기 때문임!

❗️문제점 2

호출에 대한 결과값을 상수에 담아 사용하는 것이 불가능하다.

결과 값이 완전한 데이터가 아니라 Promise의 형태로 들어오는 것을 확인할 수 있다.

3️⃣ Await/Async

await라는 것은 아무데서나 가능하지 않음
promise를 기다리는 애임!
뒤에 있는애가 promise면 .then으로 활용가능
혹은 await로 기다릴 수 있음 둘중에 하나 가능함!!!

직관적으로 순서도 꼬이지 않은 쉬운 코드를 구현가능해짐.


✔️ Promise를 기다리는 두가지 방법!

<!DOCTYPE html>
<html lang="ko">
  <head>
    <title>PROMISE PRACTICE</title>
    <script>
      const onClickThen = () => {
        new Promise((resolve, reject) => {
          try {
            //API 요청 하면?
            setTimeout(() => {
              const response = "Success"; //2초 걸려서 백엔드에서 "Success"라는 데이터 받아옴
              resolve(response); //res 성공시 실행
            }, 2000);
          } catch (error) {
            reject("ERROR!!!!!"); //err 실패시 실행
          }
        })
          .then((res) => {
            console.log(res); //""Success"
          })
          .catch((err) => {
            console.log(err); //"ERROR!!!!!"
          });
        //     const result = await setTimeout(() => {
        //       const response = "Success"; //2초 걸려서 백엔드에서 "Success"라는 데이터 받아옴
        //     }, 2000);
        // console.log(result); //이방법은 안됨. 프로미스를 통해 백엔드에서 데이터받아올 때까지 기다리는 방법
      };
      const onClickAwait = async () => {
        const result = await new Promise((resolve, reject) => {
          try {
            //API 요청 하면?
            setTimeout(() => {
              const response = "Success"; //2초 걸려서 백엔드에서 "Success"라는 데이터 받아옴
              resolve(response); //res 성공시 실행
            }, 2000);
          } catch (error) {
            reject("ERROR!!!!!"); //err 실패시 실행
          }
        });
        console.log(result); // "Success" 출력!
      };
    </script>
  </head>
  <body>
    <button onclick="onClickThen()">Promise 실행(.then)</button>
    <button onclick="onClickAwait()">Promise 실행(await)</button>
  </body>
</html>


[quiz]

import axios from "axios";
import { useState } from "react";
export default function CallBack() {
  const [callback, setCallback] = useState([]);
  const myCallback = () => {
    const aa = new XMLHttpRequest();
    console.log(aa, "aa");
    aa.open("get", `http://numbersapi.com/random?min=1&max=200`);
    // //  const result = await aa.send(); //요청
    aa.send();
    aa.addEventListener("load", (res) => {
      const num = res.target.response.split(" ")[0]; //랜덤숫자를 가져옴.
      console.log(num, "num");
      const bb = new XMLHttpRequest();
      bb.open("get", `https://koreanjson.com/posts/${num}`);
      bb.send();
      bb.addEventListener("load", (res) => {
        //load되면 res받은 결과 넣어서 콜백실행해줘~!
        console.log(res, "res"); // API 요청 결과
        const userId = JSON.parse(res.target.response).UserId; //객체로 변환후 useId뽑아서 변수에 저장
        console.log(userId, "userID");
        const cc = new XMLHttpRequest();
        cc.open("get", `https://koreanjson.com/posts?userId=${userId}`);
        cc.send();
        console.log(cc, "cc");
        cc.addEventListener("load", (res) => {
          console.log(res, "res"); //최종 API 요청 결과
     console.log(JSON.parse(res.target.response));
        });
      });
    }); // await없던 때 콜백함수보내서 실행시켜주기(함수선언부분)
  };
  const myPromise = () => {
    axios
      .get(`http://numbersapi.com/random?min=1&max=200`)
      .then((res) => {
        const num = res.data.split(" ")[0];
        return axios.get(`https://koreanjson.com/posts/${num}`);
      })
      .then((res) => {
        const userId = res.data.UserId;
        return axios.get(`https://koreanjson.com/posts?userId=${userId}`);
      })
      .then((res) => {
        console.log(res.data);
      });
  };
  const myAsyncAwait = async () => {
    const res1 = await axios.get("http://numbersapi.com/random?min=1&max=200");
    const num = res1.data.split(" ")[0];
    const res2 = await axios.get(`https://koreanjson.com/posts/${num}`);
    const userId = res2.data.UserId;
    const res3 = await axios.get(
      `https://koreanjson.com/posts?userId=${userId}`
    );
    console.log(res3.data);
  };
  return (
    <>
      <span>
        {callback.map((el) => (
          <div key={el.title}>{el.title}</div>
        ))}
      </span>
      결과:<button onClick={myCallback}>Callback</button>
      결과:<button onClick={myPromise}>Promise</button>
      결과:<button onClick={myAsyncAwait}>Async/Await</button>
    </>
  );
}

span 태그는 콜백 함수의 결과를 보여주기 위한 역할!
useState 훅을 사용하여 callback 상태 변수와 setCallback 함수를 정의하고,
이 변수를 map 함수를 사용하여 span 태그에 출력한다.

profile
JUST DO WHATEVER

0개의 댓글