30일차[async / await / try - catch]

진하의 메모장·2025년 2월 18일
2

공부일기

목록 보기
36/66
post-thumbnail

2025 / 02 / 18

오늘 수업 시간에는 async / await의 사용과 try - catch문의 사용 방법을 배웠습니다.
기존에 fetch함수와 then( )을 사용할 때와는 다르게 내용이 확 와닿지는 않습니다..
C# 세미나를 했을 때 내용 발표를 해본 경험이 있어서 개념 자체는 어렵진 않았습니다.



💌 Async / Await

  • Async와 Await는 비동기 처리 코드를 더 간단하고 직관적으로 작성할 수 있게 해주는 JavaScript의 키워드입니다.
  • Promise 기반으로 동작하지만, then( ) 메서드나 .catch( )와 같은 방식보다 코드를 더 간결하고 가독성 있게 만들어 줍니다.

1) Async

  • async 키워드는 함수 앞에 사용되며, 해당 함수가 Promise를 반환하도록 합니다.
  • async 함수는 항상 Promise를 반환하므로, 반환값을 처리하기 위해서는 .then( ) 또는 await를 사용할 수 있습니다.
async function example() {
  return "Hello, World!";
}

example().then(result => console.log(result));  // "Hello, World!"


2) Await

  • await 키워드는 async 함수 안에서만 사용할 수 있습니다.
  • await는 Promise가 처리될 때까지 기다리며, Promise가 해결되면 그 값을 반환합니다.
  • await를 사용하면 Promise의 결과를 바로 받을 수 있어서 코드가 동기식처럼 작성됩니다.
async function fetchData() {
  const response = await fetch('https://api.example.com/data');
  const data = await response.json();
  return data;
}


💌 try-catch

  • 자바스크립트에서 에러를 처리하는 방법으로 try-catch 문을 사용할 수 있습니다.
  • 코드 실행 중에 발생할 수 있는 예외 상황을 처리하기 위해 사용됩니다.
  • try 블록 - 실행할 코드를 작성합니다.
  • catch 블록 - try 블록에서 에러가 발생하면 이 곳에서 처리합니다.
  • finally 블록 - 에러 여부와 상관없이 항상 실행됩니다.
try {
  const result = riskyFunction();
} catch (error) {
  console.log("에러 발생: ", error);
} finally {
  console.log("무조건 실행");
}


💌 Async / Await + Try-Catch

  • Async / Await와 Try-Catch를 결합하면 비동기 코드에서 발생할 수 있는 에러를 효과적으로 처리할 수 있습니다.
  • 비동기 함수 내에서 발생할 수 있는 에러를 catch로 잡을 수 있어 더 안정적인 코드를 작성할 수 있습니다.
async function fetchData() {
  try {
    const response = await fetch('https://api.example.com/data');
    const data = await response.json();
    return data;
  } catch (error) {
    console.log("에러 발생: ", error);
  } finally {
    console.log("데이터 fetching 완료");
  }
}


💌 fetch & async/await

  • fetch와 async/await를 사용한 비동기 처리 방식을 비교해보았습니다.

1) fetch와 then( ) 사용

  • fetch를 사용해서 데이터를 받아올 때, then( ) 방식은 Promise의 .then( )을 사용하여 비동기 처리를 합니다.
fetch("https://jsonplaceholder.typicode.com/posts/2")
  .then((response) => response.json())  // 첫 번째 then()에서 response를 json으로 파싱
  .then((json) => console.log(json))     // 두 번째 then()에서 json 데이터 출력
  .catch((error) => console.log("오류 발생", error));  // 에러 처리

첫 번째 then( )

  • response.json()을 호출하여 서버 응답을 JSON 형식으로 파싱합니다.
  • 비동기적으로 처리되므로 Promise를 반환합니다.

두 번째 then( )

  • 파싱된 JSON 데이터를 가져와서 출력합니다.

catch( )

  • fetch 호출이나 데이터 파싱 과정에서 발생할 수 있는 에러를 처리합니다.


2) async/await 사용

  • await를 사용하여 비동기적인 fetch 요청을 더 직관적으로 처리합니다.
  • 코드가 동기식처럼 보이게 만들어 가독성을 높입니다.
async function runner(num) {
  try {
    // fetch에 대한 성공 값으로 Response 객체를 반환한다.
    const response = await fetch(
      `https://jsonplaceholder.typicode.com/posts/${num}`
    );

    // json()에 대한 성공 값으로 자바스크립트 객체를 반환한다.
    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.log("오류 발생", error);  // 에러가 발생하면 이곳에서 처리
  }
}

// 받아오고 싶은 값을 넘겨준다.
// fetch url에 백틱을 사용하여 해당 인수를 넘겨준다.
runner(3);

async

  • runner 함수가 async로 선언되어 있으므로 이 함수 내에서 await을 사용할 수 있습니다.

await

  • fetch는 Promise를 반환하는 비동기 함수이므로 await를 사용해 Promise가 해결될 때까지 기다립니다.

await response.json( )

  • fetch의 Response 객체에서 JSON 데이터를 추출하는 것도 비동기 작업이므로 await을 사용하여 값을 기다립니다.

try-catch

  • fetch나 JSON 파싱에서 오류가 발생하면 catch 블록에서 처리할 수 있습니다.


💌 차이점

then( ) 방식과 async/await 방식은 비동기 코드 처리에서 같은 결과를 얻지만, 구조와 가독성에서 차이가 있습니다.

구분then( ) 사용async/await 사용
비동기 흐름    .then( )으로 비동기 흐름을 처리하고, 체이닝 방식으로 진행await로 비동기 흐름을 직관적으로 처리
에러 처리       .catch( )를 사용하여 에러를 처리try-catch를 사용하여 에러를 처리
코드 가독성     여러 줄로 나누어져 코드가 길어지며 가독성이 떨어질 수 있음코드가 동기식처럼 보이며, 더 간결하고 가독성이 좋음
코드 흐름여러 .then( ) 호출로 비동기적인 코드 흐름이 이어짐await를 사용하여 동기식처럼 코드 흐름이 자연스럽게 작성됨


💌 총정리

then( ) 사용

  • 각 .then( )과 .catch( )로 코드가 나누어져 있습니다.
  • 여러 단계로 나뉘어있는 비동기 처리가 코드에서 눈에 띄게 드러납니다.
  • 비동기 흐름이 체이닝 형태로 이어집니다.

async/await 사용

  • await를 사용하여 Promise의 결과를 기다리는 방식으로 코드가 직관적이고 동기식처럼 보입니다.
  • try-catch로 에러 처리를 통합적으로 할 수 있어서 코드가 깔끔해집니다.
  • 가독성이 뛰어나며 에러 처리가 더 명확하고 코드 흐름을 쉽게 따라갈 수 있습니다.


💌 실습하기

fetch를 사용하여 API에서 사용자 데이터를 받아오고 사용하기

  • 사용할 변수를 초기화합니다.
  • Api를 호출해 데이터를 받아오는 함수를 정의합니다.
  • 해당 함수를 호출 후 버튼 클릭 시 새로운 사용자의 데이터를 로드합니다.

1) 변수 초기화

사용할 변수를 초기화합니다.

  • HTML DOM을 사용해서 해당 태그에 접근합니다.
  • 태그에 접근한 내용은 각각의 변수에 담습니다.
const user_image = document.getElementById("user-image");
const user_name = document.getElementById("user-name");
const user_email = document.getElementById("user-email");
const user_location = document.getElementById("user-location");
const load_btn = document.getElementById("load-user");


2) fetchRandomUser 함수

Api를 호출해 데이터를 받아오는 함수를 정의합니다.

  • fetchRandomUser 함수는 사용자의 데이터를 가져오기 위한 함수입니다.
  • fetch API를 사용하여 외부에서 데이터를 요청하고, 응답받은 데이터를 HTML 요소에 표시합니다.
const fetchRandomUser = () => {
  fetch("https://randomuser.me/api/")  // API 호출
    .then((response) => {
      if (response.ok) {
        return response.json();  // 응답이 정상일 경우 JSON 데이터로 파싱
      }
    })
    .then((data) => {
      // 데이터 처리 부분
      const [user] = data.results;  // 첫 번째 사용자 데이터를 추출

      // 사용자 데이터 표시
      user_image.src = user.picture.large;  // 사용자 이미지 출력
      user_name.innerHTML = `${user.name.first} ${user.name.last}`;  // 이름 출력
      user_email.innerHTML = user.email;  // 이메일 출력
      user_location.innerHTML = user.location.country;  // 위치 출력
    })
    .catch((error) => {
      console.error("데이터 전송에 실패했습니다.", error);  // 오류 처리
    });
};

fetch("https://randomuser.me/api/")

  • fetch 함수는 API를 호출하여 데이터를 요청합니다.
  • randomuser.me API에서 랜덤 사용자 정보를 반환합니다.

.then((response) => {...})

  • fetch 함수는 비동기적으로 실행되기 때문에, .then()을 사용하여 응답을 처리합니다.
  • response.ok는 서버가 정상적으로 응답했는지 확인하는 방법입니다.

return response.json( )

  • 응답이 정상적이면 response.json( )을 호출하여 JSON 데이터를 반환합니다.

.then((data) => {...})

  • JSON 데이터가 반환되면 이 부분에서 사용자의 정보를 처리합니다.

const [user] = data.results;

  • API로부터 반환된 데이터는 results 배열 안에 있습니다.
  • 그 배열에서 첫 번째 사용자 객체를 추출합니다.(구조분해 사용)

user_image.src = user.picture.large;

  • user.picture.large에 있는 사용자 이미지 URL을 img 태그의 src 속성에 넣습니다.

user_name.innerHTML = ...:

  • 사용자 이름을 ${user.name.first} ${user.name.last} 형태로 결합하여 h2 요소에 출력합니다.

user_email.innerHTML = user.email;

  • 사용자 이메일을 p 태그에 출력합니다.

user_location.innerHTML = user.location.country;

  • 사용자의 국가를 p 태그에 출력합니다.

.catch((error) => {...})

  • fetch 요청이나 데이터 파싱 중에 에러가 발생하면 catch에서 에러를 처리합니다.
  • 콘솔에 에러 메시지를 출력합니다.


3) 호출 및 버튼 이벤트

해당 함수를 호출 후 버튼 클릭 시 새로운 사용자의 데이터를 로드합니다.

  • 스크립트가 로드될 때 한 번 호출하여 처음 사용자 데이터를 로드합니다.
  • 버튼을 클릭하면 fetchRandomUser( ) 함수가 호출되어 새로운 사용자 데이터를 불러옵니다.
fetchRandomUser();
<button id="load-user" class="load-user-btn" onclick="fetchRandomUser()">Load New User</button>


💌 전체 흐름 요약

1. 페이지 로드 시

  • fetchRandomUser() 함수가 호출되어 첫 번째 사용자 데이터를 API에서 받아옵니다.

2. 버튼 클릭 시

  • 사용자가 "Load New User" 버튼을 클릭하면, fetchRandomUser() 함수가 다시 호출되어 새로운 사용자 데이터를 API에서 받아옵니다.

3. API 응답

  • API에서 받은 데이터를 처리하여 사용자 정보(이름, 이메일, 위치, 이미지 등)를 화면에 출력합니다.

4. 에러 처리

  • 만약 API 호출이나 데이터 처리 중에 오류가 발생하면, catch에서 이를 처리하고 오류 메시지를 콘솔에 출력합니다.


💌 전체 코드

  • 위에서 스크립트 코드만 설명을 하고 있는데, 아래 코드는 HTML과 CSS를 포함한 코드입니다.
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Random User Profile</title>
    <style>
      body {
        background-color: #f4f4f4;
        display: flex;
        justify-content: center;
        align-items: center;
        height: 100vh;
        margin: 0;
      }
      .user-card {
        background: white;
        padding: 20px;
        border-radius: 10px;
        box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1);
        text-align: center;
        width: 300px;
      }
      .user-avatar {
        width: 100px;
        height: 100px;
        border-radius: 50%;
        margin-bottom: 15px;
      }
      .user-name {
        font-size: 20px;
        font-weight: bold;
        margin-bottom: 5px;
      }
      .user-email {
        font-size: 14px;
        color: #555;
        margin-bottom: 10px;
      }
      .user-location {
        font-size: 16px;
        color: #333;
        margin-bottom: 15px;
      }
      .load-user-btn {
        background-color: #007bff;
        color: white;
        border: none;
        padding: 10px 15px;
        border-radius: 5px;
        cursor: pointer;
      }
      .load-user-btn:hover {
        background-color: #0056b3;
      }
    </style>
  </head>
  <body>
    <div id="user-card" class="user-card">
      <img id="user-image" src="" alt="User Avatar" class="user-avatar" />
      <h2 id="user-name" class="user-name"></h2>
      <p id="user-email" class="user-email"></p>
      <p id="user-location" class="user-location"></p>
      <button id="load-user" class="load-user-btn" onclick="fetchRandomUser()">
        Load New User
      </button>
    </div>

    <script>
      // api를 요청하여 받은 데이터를 넣을 요소 가져오기
      const user_image = document.getElementById("user-image");
      const user_name = document.getElementById("user-name");
      const user_email = document.getElementById("user-email");
      const user_location = document.getElementById("user-location");
      const load_btn = document.getElementById("load-user");

      // 데이터 요청 함수
      const fetchRandomUser = () => {
        fetch("https://randomuser.me/api/")
          .then((response) => {
            if (response.ok) {
              return response.json();
            }
          })
          .then((data) => {
            // 구조분해를 사용하여 변수에 넣기
            const [user] = data.results;
            console.log(user);

            //  user.picture.large에 있는 사진을 user_image의 src 속성에 넣기
            user_image.src = user.picture.large;

            const name = `${user.name.first} ${user.name.last}`;
            user_name.innerHTML = name;

            const email = user.email;
            user_email.innerHTML = email;

            const location = user.location.country;
            user_location.innerHTML = location;
          })
          .catch((error) => {
            console.error("데이터 전송에 실패했습니다.", error);
          });
      };

      fetchRandomUser();
    </script>
  </body>
</html>



30일차 후기

  • fetch 함수와 Promise 객체에 익숙해지기 전에 async/await를 배워서 헷갈렸습니다.
  • API로부터 데이터를 받아오고, 해당 데이터를 사용해보는 것까지 실습을 하면서... "앞으로의 프로젝트에는 많은 API가 쓰이겠지"라는 생각이 들어서 더 걱정입니다.
  • 생각만 하고 보니 막막하기도 해서 개념을 확실히 이해하고 넘어가야할 것 같습니다.
  • 아니 근데 왜 자꾸 실습하는데 async가 오타가 나는 걸까요.. 진짜 의문입니다..
  • DOM 요소에 동적으로 반영하는 것은 어느정도 익숙해진 것 같습니다. ‹( '▿' )›
  • 하루 수업 진도가 적은 편은 아닌 것 같아서 복습을 꾸준히 해야겠습니다. ૮(ॢ ᵕㅅᵕ ॢ )ა
profile
૮꒰ ྀི〃´꒳`〃꒱ა

0개의 댓글