본문 바로가기
☁️ 구름 X kakao DeepDive/☁️ HTML CSS JS

[JavaScript] 비동기요청에서 Callbacks, Promise 그리고 Async/Await

by 뽀짜꼬 2025. 1. 9.
728x90
반응형

자바스크립트는 싱글스레드

그래서 하나의 일을 할 때 하나밖에 못함 → 그런데 그 하나의 일이 오래 걸리는 일이면?

→ 다른 작업들은 그 오래걸리는 일이 끝날 때 까지 오~~래 기다려야한다.

⇒ 이러한 문제점을 해결하기 위해서 비동기로 어떠한 일을 수행하게 된다.

만약 비동기 요청이 여러 개 있을 때 하나의 요청이 다른 요청의 결과에 의존한다면?

 

위의 소스코드에서 처럼 둘 다 비동기 요청을 보내는데 두 번째 요청에서 첫 번째 요청의 결과가 필요할 수가 있다.

하지만, 둘 다 병렬적으로 요청을 보내기 때문에 response1을 가지기 전에 두 번째 요청이 보내지게 된다.

⇒ 이 문제를 어떻게 해결할까?

 

Callback 함수, Promise, Async Await 를 이용하는 세 가지 방법이 있다.


Callback 콜백 함수

특정 함수에 매개변수로 전달된 함수를 의미함. 그리고 그 콜백함수는 함수를 전달받은 함수 안에서 호출됨

  • 콜백 사용의 단점
    • 소스코드를 보는 데 가독성이 떨어짐
    • 에러 처리를 한다면 모든 콜백에서 각각 에러 핸들링을 해주어야 함

Promise

Promise 객체는 new 키워드와 생성자를 통해 만든다.

new Promise(resolve, reject)

 

생성자는 매개변수로 “실행함수”를 받는다. 이 함수는 매개변수로 두 가지 함수를 받아야 한다.

  • 첫번째 함수 resolve : 비동기 작업을 성공적으로 완료해 결과를 값으로 반환할 때 호출
  • 두번째 함수 reject : 작업이 실패하여 오류의 원인을 반환할 때 호출.

⇒ 즉, 성공시 resolve, 실패시 reject 이다.

const myFirstPromise = new Promise((resolve, reject) => {
    // Do something asynchronous which eventually calls either:
    //
    // resolve(someValue);  // if the operation is successful
    // or
    // reject("failure reason");  // if there is an error
});
  • Promise 는 자바스크립트 비동기 처리에 사용되는 객체
  • Promise 객체는 비동기 작업이 맞이할 미래의 완료 또는 실패와 그 결과값을 나타낸다.
let myFirstPromise = new Promise((resolve, reject) => {
    // 우리가 수행한 비동기 작업이 성공한 경우 resolve(...)를 호출하고,
    // 실패한 경우 reject(...)를 호출합니다.

    // 이 예제에서는 setTimeout()을 사용해 비동기 코드를 흉내냅니다.
    // 실제로는 여기서 XHR이나 HTML5 API를 사용할 것입니다.
    setTimeout(function() {
        resolve("성공!"); // 와! 문제 없음!
    }, 250);
});

myFirstPromise.then((successMessage) => {
    // successMessage는 위에서 resolve(...) 호출에 제공한 값입니다.
    // 문자열이어야 하는 법은 없지만, 위에서 문자열을 줬으니 아마 문자열일 겁니다.
    console.log("와! " + successMessage);
});

 

위의 기본 코드를 바탕으로 작성해보면, 아래와 같이 적을 수 있는데

function fetchData() {
    return new Promise((resolve, reject) => {
        const success = true; // 성공 여부를 나타내는 변수
        if (success) {
            resolve('성공'); // 성공일 때 호출
        } else {
            reject('실패'); // 실패일 때 호출
        }
    });
}

fetchData()
    .then(function(result) {
        console.log(result); // 성공 
    })
    .then(function(error) {
        console.log(error); // undifined
    });

 

⇒ 그런데 실제로는 에러 처리시 then 하는게 아니라 아래의 사진처럼 catch로 처리한다.

Promise는 다음 중 하나의 상태를 가진다.

대기(pending) : 비동기 처리 로직이 아직 완료되지 않은 상태

  • 아직 result는 없어욤

이행(fullfilled) : 비동기 처리가 완료되어 프로미스가 결과 값을 반환해준 상태

거부(rejected) : 비동기 처리가 실패하거나 오류가 발생한 상태

 

대기 중인 프로미스는 값과 함께 이행할 수도, 어떤 이유(오류)로 인해 거부될 수도 있다.

  • 이행이나 거부될 때, Promise의 then 메서드에 의해 대기열 (큐)에 추가된 처리기들이 호출된다.
  • 이미 이행했거나 거부된 프로미스에 처리기를 연결해도 호출됨. → 비동기 연산과 처리기 연결 사이에 경합 조건은 없다.

Promise.all()

순회 가능한 객체에 주어진 모든 프로미스가 이행한 후, 혹은 프로미스가 주어지지 않았을 때 이행하는 Promise 를 반환한다. 주어진 프로미스중 하나가 거부하는 경우, 첫 번째로 거절한 프로미스의 이유를 사용해 자신도 거부한다.

 

arrays안에 순회 가능한 객체를 넣어줌. (배열과 같은)

세개가 다 이행 (fullfill)이 된 후 한번에 반환 (하나라도 reject되면 reject 반환)

 

Promise.race()

Promise 객체를 반환하는데, iterable 안에 있는 프로미스 중에 가장 먼저 완료된 것의 결과값으로 그대로 이행하거나 거부한다.

 

먼저 완료된것의 결과값을 보여줌.


Async / Await

문법적으로 훨씬 깔끔해지게 만든건데용

  • 비동기 코드지만 마치 동기 코드처럼 보인다
    • 하나 끝나면 기다렸다 하게 하고.. 이렇게
  • Promise에 then 메서드를 체인 형식으로 호출하는것 보다 가독성이 좋다
  • await는 async 내부 함수에서만 사용할 수 있다.
  • 동기식 코드에서 쓰는 try..catch 구문을 async/await 구조에서 사용할 수 있다.
728x90
반응형