중앙정보기술인재개발원/HTML&CSS&JS

[JS] | 비동기, Promise,async,await

soidev 2025. 4. 23. 11:14

비동기

   시간이 오래 걸리는 작업을 따로 처리

  • 코드 실행 도중에도 다음 코드가 먼저 실행될 수 있음
  • 자바에선 thread같은 개념
  • 예시
    const pp1 = new Promise((resolve, reject) => {
      const value = 30;
      if (value < 0) {
        reject("에러 발생!");
      }
      resolve(value); //  성공 시 결과 전달 (return 같은 역할)
    });

✅ 동기(Synchronous) 처리란?

  • 코드가 위에서 아래로 순서대로 실행됨
  • 앞 코드가 끝나야 다음 코드가 실행됨
  • 보통 동기식 코드임

✅ Promise란?

  • 비동기 작업을 처리하기 위한 객체
  • 성공하면 resolve(), 실패하면 reject()를 호출함
Promise 기반 비동기 코드의 기본 구조
const pp1 = new Promise((resolve, reject) => {
  const value = 30;
  if (value < 0) {
    reject("문제가 좀 있는데?");
  }
  resolve(value);
});

 

  • new Promise() 내부 코드는 바로 실행됨
  • resolve(value)가 호출되면 .then()으로 넘어감
  • reject()되면 .catch()로 감

✅ 즉, reject()는

  • 비동기 코드에서 오류나 예외 상황이 발생했을 때,
  • 코드가 강제 종료되지 않도록 하고,
  • .catch()로 에러를 안전하게 넘겨서 처리할 수 있게 해줌!

 

 pp1.then(result => {
  console.log(result); // 30 출력
}).catch(message => {
  console.log(message); // 에러 메시지 출력
});

 

👉 여기서 중요한 건:

  • doSomethingAsync()는 Promise를 return
  • 그래야 .then()을 붙여서 결과를 받을 수 있음
  • return 안 하면? .then()은 못 붙임 → 결과도 못 씀

4. 비동기를 동기처럼 실행하는 법 (체이닝)

🧠 그래서 왜 동기처럼 쓰고 싶을까?

비동기 코드를 then안에 계속 넣고 넣고 쓰면 너무 가독성도 나쁘고 유지보수도 힘들다

plusTwoValue(5, 3).then(result => {
  console.log(result); // 8
  plusTwoValue(2, 7).then(r => {
    console.log(r); // 9
  });
});

➡️ 이렇게 쓰면 코드가 동기처럼 읽히면서도 실제로는 비동기로 동작해., 콜백함수라고도 불림

▶ 예시

1. 서버에서 데이터 받아오기 (예: 게시판 글 목록)

예를 들어, 게시판에서 글 목록을 서버에서 받아오는 경우

사용자가 버튼을 클릭하면 글 목록을 서버에서 비동기적으로 받아와서 화면에 보여줘야 할 때.

async function getPostList() {
    try {
        const response = await fetch('/api/posts'); // 서버에서 게시글 목록을 받아옴
        const posts = await response.json(); // JSON으로 변환
        console.log(posts); // 받아온 데이터로 화면을 업데이트하는 부분
    } catch (error) {
        console.error("게시글을 가져오는 중 오류 발생", error);
    }
}

// 예: 게시글 목록을 가져오는 버튼 클릭 시 호출
document.querySelector("#loadPostsBtn").addEventListener("click", getPostList);

2. 사용자 로그인 처리

로그인 버튼을 클릭했을 때,

사용자가 입력한 정보로 서버에 인증 요청을 보내고 결과를 기다린 후, 로그인 성공 또는 실패 처리를 할 때.

async function loginUser(username, password) {
    try {
        const response = await fetch('/api/login', {
            method: 'POST',
            body: JSON.stringify({ username, password }),
            headers: { 'Content-Type': 'application/json' }
        });
        const data = await response.json();
        if (data.success) {
            console.log("로그인 성공");
            // 로그인 후 화면 업데이트 (예: 대시보드로 이동)
        } else {
            console.log("로그인 실패");
        }
    } catch (error) {
        console.error("로그인 중 오류 발생", error);
    }
}

// 예: 로그인 폼 제출 시 호출
document.querySelector("#loginForm").addEventListener("submit", function (e) {
    e.preventDefault();
    const username = e.target.username.value;
    const password = e.target.password.value;
    loginUser(username, password);
});

❌ return 안 하면 무슨 일이 생기냐?

  • wrong()은 Promise를 return 안 했기 때문에
  • .then()이 붙은 시점에서 아무것도 안 돌려줌
  • 즉, 비동기 동작은 했지만 결과를 쓸 수 없음

💡 그래서 결론:

비동기 코드를 제대로 "연결해서" 쓰려면 무조건 return 해줘야 함!!

 

🔥 그래서 실무에서는?

  • 복잡한 비동기 처리 = async/await가 훨씬 가독성도 좋고 편함
  • then() 계속 쓰면 콜백지옥처럼 길어짐 → await로 해결

Async, Await

   Promise 기반으로, 편하게 사용하기 위해 나온 문법

  • async는 promise기반이라 또 따로 설정 안 해줘도 then 활용 가능
  • 비동기 함수는 목적이 사실상 비동기임
  • 그래서 그걸 동기화 시키는 것은 많은 생각을 하고 해야함

🔑 async와 await의 관계

  • async: 함수가 비동기적으로 실행된다는 걸 명시해. 이걸 사용하면 해당 함수는 항상 Promise를 반환
  • await: async 함수 내에서만 사용 가능하고, Promise가 끝날 때까지 기다리기 위해 사용

왜 이런 규칙이 있을까?

 await는 Promise가 해결될 때까지 기다리기 때문에, Promise가 동기적으로 기다려야 할 부분을 처리하는 역할
그래서 비동기 함수 안에서만 동작하게 만들음. 만약 async 없이 await를 쓰면, JavaScript가 await가 무엇을 기다려야 하는지 제대로 알 수 없어서 에러가 남.

 

😎 async와 await의 장점

  1. 가독성: 비동기 작업을 동기 코드처럼 쉽게 읽을 수 있음.
  2. 에러 처리: try/catch로 비동기 작업의 에러를 동기 코드처럼 처리할 수 있음.
async function getData() {
    try {
        let result = await fetch('https://api.example.com/data');
        let data = await result.json();
        console.log(data);
    } catch (error) {
        console.log('에러 발생:', error);
    }
}

1. async는 Promise 기반:

  • async 함수는 항상 Promise를 반환.
    즉, async 함수 내에서 리턴하는 값은 자동으로 Promise로 감싸져서 반환됨.
  • 예를 들어, async 함수가 return 10을 반환하면, 사실 그 값은 **Promise.resolve(10)**으로 감싸져서 반환됨.

2. await는 Promise의 then 기반:

  • await는 사실 Promise의 then을 더 간단하게 사용한 것이다.
  • await는 Promise가 해결될 때까지 기다린 후 결과를 반환, 이는 then의 방식과 같지만, 코드가 더 깔끔하고 직관적임.