콜백 함수 (Callback Function)
- 비동기 처리의 핵심은 Web API로 들어오는 순서가 아니라 작업이 완료되는 순서에 따라 처리한다는 것!
- 그런데 이는 개발자 입장에서 코드의 실행 순서가 불명확하다는 단점이 있음
- 이와 같은 단점은 실행 결과를 예상하면서 코드를 작성할 수 없게 함
콜백 지옥 (Callback Hell)
- 콜백 함수는 연쇄적으로 발생하는 비동기 작업을 순차적으로 동작할 수 있게 함
- 보통 어떤 기능의 실행 결과를 받아서 다른 기능을 수행하기 위해 많이 사용하는데, 이 과정을 작성하다 보면 비슷한 패턴이 계속 발생하게 됨
- A를 처리해서 결과가 나오면, 첫 번째 callback 함수를 실행하고
- 첫 번째 callback 함수가 종료되면, 두 번째 callback 함수를 실행하고
- 두 번째 callback 함수가 종료되면, 세 번째 callback 함수를 실행하고 …
- 비동기 처리를 위한 콜백을 작성할 때 마주하는 문제를 Callback Hell(콜백 지옥)이라 하며, 그때의 코드 작성 형태가 마치 “피라미드와 같다”고 해서 “Pyramid of doom(파멸의 피라미드)”라고도 부름

요약
- 콜백 함수는 비동기 작업을 순차적으로 실행할 수 있게 하는 반드시 필요한 로직
- 비동기 코드를 작성하다 보면 콜백 함수로 인한 콜백 지옥(callback hell)은 반드시 나타나는 문제
프로미스 (Promise)
- Callback Hell 문제를 해결하기 위해 등장한 비동기 처리를 위한 객체
- “작업이 끝나면 실행 시켜줄게”라는 약속(promise)
- 비동기 작업의 완료 또는 실패를 나타내는 객체
- Promise 기반의 클라이언트가 바로 클라이언트 통신에 많이 사용하는 Axios 라이브러리
- “Promise based HTTP client for the browser and node.js”
- 성공에 대한 약속
then()
- 실패에 대한 약속
catch()
then & catch
then(callback)
- 요청한 작업이 성공하면 callback 실행
- callback은 이전 작업의 성공 결과를 인자로 전달 받음
catch(callback)
- then()이 하나라도 실패하면 callback 실행
- callback은 이전 작업의 실패 객체를 인자로 전달 받음
- then과 catch 모두 항상 promise 객체를 반환
- axios로 처리한 비동기 로직이 항상 promise 객체를 반환
- 그래서 then을 계속 이어 나가면서 작성할 수 있던 것
axios.get('요청할 URL').then(...).then(...).catch(...)
axios.get('요청할 URL’)
.then(성공하면 수행할 1번 콜백함수)
.then(1번 콜백함수가 성공하면 수행할 2번 콜백함수)
.then(2번 콜백함수가 성공하면 수행할 3번 콜백함수)
...
.catch(실패하면 수행할 콜백함수)
비동기 콜백 vs Promise
- promise 방식은 비동기 처리를 마치 우리가 일반적으로 위에서 아래로 적는 방식처럼 코드를 작성할 수 있음
work1(function () {
work2(result1, function (result2) {
work3(result2, function (result3) {
console.log('최종 결과 :' + result3)
})
})
})
work1()
.then((result1) => {
return result2
})
.then((result2) => {
return result3
})
.catch((error) => {
})
Promise가 보장하는 것 (vs 비동기 콜백)
- 비동기 콜백 작성 스타일과 달리 Promise가 보장하는 특징
- callback 함수는 JavaScript의 Event Loop가 현재 실행 중인 Call Stack을 완료하기 이전에는 절대 호출되지 않음
- Promise callback 함수는 Event Queue에 배치되는 엄격한 순서로 호출됨
- 비동기 작업이 성공하거나 실패한 뒤에 .then() 메서드를 이용하여 추가한 경우에도 1번과 똑같이 동작
- .then()을 여러 번 사용하여 여러 개의 callback 함수를 추가할 수 있음 (Chaining)
- 각각의 callback은 주어진 순서대로 하나하나 실행하게 됨
- Chaining은 Promise의 가장 뛰어난 장점
Axios 실습
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
방법 1
const URL = 'https://jsonplaceholder.typicode.com/todos/1/'
const myPromise = axios.get(URL)
console.log(myPromise)

방법 2 - Chaining
myPromise
.then(response => {
console.log(response.data)
return response.data
})

axios.get(URL)
.then(response => {
console.log(1)
console.log(response)
return response.data
})
.then(response => {
console.log(2)
console.log(response)
return response.title
})
.then(response => {
console.log(3)
console.log(response)
})
.catch(error => {
console.log(error)
})

다른 표기법 (권장)
axios({
method: 'get',
url: URL,
})
.then(response => {
console.log(response)
return response.data
})
.then(response => {
console.log(response)
return response.title
})
.then(response => {
console.log(response)
})
.catch(error => {
console.log(error)
})

Promise 객체 사용하기
Promise 객체 생성하기
- Promise 객체를 생성할 때에는,
new Promise() 구문을 사용
resolve와 reject라는 두 개의 콜백 함수를 인자로 받는 함수
resolve : Promise 객체가 성공적으로 완료됐을 때 호출되는 함수
reject : Promise 객체가 실패했을 때 호출되는 함수
const promise = new Promise(function(resolve, reject) {
if (작업이 성공했을 경우) {
resolve(결과);
} else {
reject(에러);
}
});
Promise 객체의 결과 처리하기
- Promise 객체가 성공적으로 완료되면,
then() 메소드를 사용하여 결과 처리
promise.then(function(결과) {
}).catch(function(에러) {
});
Promise 객체 체이닝하기
promise.then(function(결과) {
return new Promise(function(resolve, reject) {
if (작업이 성공했을 경우) {
resolve(결과2);
} else {
reject(에러);
}
});
}).then(function(결과2) {
}).catch(function(에러) {
});