콜백 함수(callback function)
JavaScript는 비동기 처리를 위해 콜백 함수를 사용하곤 했는데, 이 전통적인 콜백 패턴은 몇 가지 한계점이 있었다.
1. callback hell로 인해 가독성이 나쁘다.
2. 비동기 처리 중 발생한 에러를 처리하기 어렵다.
3. 여러 개의 비동기 처리를 한번에 처리하기 어렵다.
➡️ ES6에서 비동기 처리를 위한 새로운 패턴으로 Promise를 도입했다.
Promise는 전통적인 콜백 패턴이 가진 단점을 보완하며, 비동기 처리 시점을 명확하게 표현할 수 있다는 장점이 있다.
: JavaScript의 비동기 처리에 사용되는 객체
Promise는 Promise 생성자 함수를 이용해 instance를 생성한다.
const promise = new Promise((resolve, reject) => {});
예시)
const promise = new Promise((resolve, reject) => {
if(비동기 작업 수행이 성공했다면..) {
resolve('결과를 표시합니다.');
} else { // 비동기 작업 수행이 실패했다면..
reject('실패 원인을 표시합니다.');
}
});
: Promise 객체는 2개의 프로퍼티를 갖는다.
: 비동기 처리가 성공했는지 실패했는지에 대한 상태
: resolve/reject 함수로부터 전달받은 값
상태 | 의미 | 구현 |
---|---|---|
pending | 비동기 처리가 수행되지 않은 상태 | 아무 함수도 호출되지 않은 상태 |
fulfilled | 비동기 처리가 수행된 상태(성공) | resolve 함수가 호출된 상태 |
rejected | 비동기 처리가 수행된 상태(실패) | reject 함수가 호출된 상태 |
settled | 비동기 처리가 수행된 상태(성공/실패) | resolve/reject 함수가 호출된 상태 |
pending
: Promise 생성자 함수의 인자로 전달받은 콜백 함수는 비동기 처리 작업을 수행하는데, 작업을 수행하기 전의 대기 상태이다.
pending
undefined
const printHello = new Promise((resolve, reject) => { });
printHello;
fulfilled
: 콜백 함수가 수행한 비동기 작업이 성공한 경우, Promise의 상태는 fulfilled 상태가 되고 콜백 함수의 인자로 전달받은 resolve 함수를 호출한다.
resolve
resolve() 함수로부터 전달받은 값
const printHello = new Promise((resolve, reject) => {
let a = 1 + 1;
if(a === 2) {
resolve('이행되었습니다.');
} else {
reject('거절되었습니다.');
}
});
printHello;
rejected
: 콜백 함수가 수행한 비동기 작업이 실패한 경우, Promise의 상태는 rejected 상태가 되고 콜백 함수의 인자로 전달받은 reject 함수를 호출한다.
rejected
reject 함수로부터 전달받은 값
const printHello = new Promise((resolve, reject) => {
let a = 1 + 99;
if(a === 2) {
resolve('이행되었습니다.');
} else {
reject('거절되었습니다.');
}
});
printHello;
.then()
Promise.prototype.then()
: Promise를 반환하므로 메서드 체이닝을 할 수 있다.
const a = new Promise((resolve, reject) => {
resolve(1);
})
// 이때 프로미스 객체는 state : fulfilled, result : 1 이다.
a.then((num) => num + 1) // state : fulfilled, result : 2
.then((num) => num + 1) // state : fulfilled, result : 3
.then((num) => num + 1) // state : fulfilled, result : 4
.catch()
Promise.prototype.catch
: Promise를 반환하며 메서드 체이닝을 할 수 있다.
에러가 난 경우 실행되는 메서드이다.
const printHello = new Promise((resolve, reject) => {
let a = 1 + 99;
if(a === 2) {
resolve('이행되었습니다.');
} else {
reject('거절되었습니다.');
}
});
printHello
.then((msg) => {
console.log('then : ' + msg)
})
.catch((msg) => {
console.log('catch : ' + msg)
});
// catch : 거절되었습니다.
Promise.all()
Promise.all([prms1, prms2...])
: 여러 개의 Promise를 한 번에 처리하는 메소드
Promise.all()
에 전달된 배열 안의 Promise들의 순서대로 결과로 반환되는 배열의 요소의 순서가 정해진다.Promise.all()
은 즉시 거부되며 catch()
메소드를 실행한다.Promise.all([
new Promise(resolve => setTimeout(() => resolve(1), 3000)),
new Promise(resolve => setTimeout(() => resolve(2), 2000)),
new Promise(resolve => setTimeout(() => resolve(3), 1000))
])
.then((result) => console.log(result));
// 프라미스 전체가 처리된 후(3초 후) [1, 2, 3]이 반환된다.
위 코드의 각 Promise를 변수에 할당하여 더 간단하게 작성해보면, 아래처럼 작성할 수 있다.
const one = new Promise((resolve) => setTimeout(() => resolve(1), 3000));
const two = new Promise((resolve) => setTimeout(() => resolve(2), 2000))
const three = new Promise((resolve) => setTimeout(() => resolve(3), 1000));
Promise.all([one, two, three])
.then((result) => console.log(result));
// [1, 2, 3]
: 여러 개의 Promise가 계속해서 중첩(nesting)되어 코드가 복잡해지고, 가독성이 떨어지는 것
❔ 학습 후 궁금한 점
Promise.all()
에서 Promise들 중 하나라도 에러가 발생하면, 에러 어디서 발생한 건지 어떻게 아는지?- Promise hell의 개념을 제대로 이해하지 못했다 😂
이 글은 아래 링크를 참고하여 작성한 글입니다.
https://poiemaweb.com/es6-promise