Promise와 Callback의 비교

wonway·2024년 2월 19일
0
post-thumbnail

요약

Promise, Callback 모두 비동기 작업을 처리하는 방법이다. Callback이 더 오래된 기술이며 선행단계가 완료된 후 실행할 함수를 Callback()에 넣어서 실행한다. 이 방법은 선행 단계가 중첩될 경우 가독성이 나빠지고과 유지보수가 어려워지는 단점이 있다. Promise는 비동기 작업이 실행 된 후 반환되는 객체이다. Promise객체는 성공과 실패의 결과가 담겨있으며 then() 메서드가 성공처리, catch() 메서드가 실패처리, finally() 메서드는 성공실패와 관계없이 실행되어 공통적인 정리 작업에 사용하기 좋다. 이렇게 Promise는 동작에 대한 분기를 선언적으로 하기 때문에 가독성과 유지보수가 용이하다.

Callback

Callback이 더 오래된 기술이며 비동기 작업이 완료된 후 실행할 함수를 인자로 전달하는 방식이다. 여러 비동기 방식을 연결할 때 콜백함수가 중첩되는 콜백지옥이 발생할 수 있다.

Callback의 예시 코드는 다음과 같다.

//
document.getElementById('myButton').addEventListener('click', function() {
  alert('버튼이 클릭되었습니다!');
});

일반적인 이벤트 리스너 코드이다.

여기에 들어간 function이 선행 단계에 의존하여 동작하는 함수, Callback 함수이다.

만약 선행 단계가 중첩된다면 Callback지옥이라 불리는 현상이 발생한다.

// 첫 번째 API 호출
getData(function(a) {
    // 두 번째 API 호출
    processData(a, function(b) {
        // 세 번째 API 호출
        saveData(b, function(c) {
            // 결과 처리
            console.log(c);
            // 더 많은 중첩된 콜백이 있을 수 있음
        }, function(error) {
            console.error('세 번째 호출에서 에러 발생', error);
        });
    }, function(error) {
        console.error('두 번째 호출에서 에러 발생', error);
    });
}, function(error) {
    console.error('첫 번째 호출에서 에러 발생', error);
});

이런 코드는 가독성과 유지 보수가 어려워진다.

Promise

Promise는 ES6 사양에 도입됐으며 비동기 작업의 성공인 완료와 실패를 나타내는 객체이다.

then(), catch()를 통해 성공/실패 완료 후 동작을 선언적으로 할 수 있다.

finally()는 성공 실패 여부와 관계없이 동작한다. 공통 로직을 이쪽으로 분리하면 좋다.

// getData 함수가 API를 호출하여 데이터를 가져오는 로직
function getData() {
    return fetch('https://api.example.com/data')
        .then(response => {
            if (!response.ok) {
                throw new Error('Network response was not ok');
            } // 에러 객체를 던진다. then()을 건너뛰고 가장 가까운 catch()에서 받는다.
            return response.json(); // 데이터를 JSON으로 파싱
        });
}

// processData 함수가 받은 데이터를 가공하기 위해 다른 API를 호출하는 로직
function processData(data) {
    // 여기서는 data를 처리하여 요청 본문에 포함시키는 예시입니다.
    // 실제 요청에서는 data를 적절히 가공하여 사용해야 합니다.
    return fetch('https://api.example.com/process', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify(data),
    })
    .then(response => {
        if (!response.ok) {
            throw new Error('Network response was not ok');
        }
        return response.json(); // 처리된 데이터를 JSON으로 파싱
    });
}

// saveData 함수가 가공된 데이터를 저장하기 위해 또 다른 API를 호출하는 로직
function saveData(processedData) {
    // 마찬가지로 processedData를 요청 본문에 포함시킵니다.
    return fetch('https://api.example.com/save', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify(processedData),
    })
    .then(response => {
        if (!response.ok) {
            throw new Error('Network response was not ok');
        }
        return response.json(); // 최종 저장 결과를 JSON으로 파싱
    });
}
// 위의 코드는 api 호출 결과 Promise 객체를 반환한다. 
// 아래의 코드는 Promise 객체를 통해 콜백지옥이 아닌 방법으로 비동기작업을 조절한다. 

// Promise를 사용한 비동기 작업 체이닝
getData()
    .then(processData) // 앞의 단계에서 반환된 프로미스가 성공적으로 해결되면, 그 결과가 processData 함수의 인자로 전달된다.
    .then(saveData)
    .then(result => {
        console.log(result); // 최종 결과 처리
    })
    .catch(error => {
        console.error(error); // 어느 단계에서든 에러 발생 시 처리
    });

then()은 순차적으로 동작하므로 코드의 진행 순서가 같은 깊이에 위치하니 읽기 편리하다.


더 알아볼 개념

async/await : Promise의 비동기 코드를 동기 코드처럼 다루는 문법

profile
문제를 컴퓨터로 해결하는 데서 즐거움을 찾는 프론트엔드 개발자

0개의 댓글