비동기 : 특정 코드의 실행이 완료될 때까지 기다리지 않고 다음 코드를 먼저 수행하는 방식.
콜백 함수 : 비동기 작업이 완료되면 호출되는 함수로 비동기 함수의 매개변수로 함수 객체를 넘겨준다.
콜백 HEll : 여러 개의 비동기 작업을 순차적으로 수행해야 할 때는 콜백 함수가 중첩되어 코드의 깊이가 깊어지는 현상
JS의 비동기 처리를 하면서 콜백함수를 연달아 쓰고 Callback Hell을 보면서 코드의 가독성을 떨어지고 코드의 흐름이 망가지는 것을 봤다.
Callback + Asynchronous를 한 Promise 객체를 통해서 비동기를 많이 해도 코드의 깊이가 깊어지지 않게 표현할 수 있다.
비동기 작업의 성공과 실패를 나타낸다.
function caller(callee) {
var produced = producing()
callee(produced)
}
caller(function callee(produced) {
consuming(produced)
})
Promise 의 Producing 은 성공 / 실패 2개의 상태로 나뉘며, 성공 / 실패 에 따른 콜백 설정한다.

[ Pending → Fulfilled(성공, Resolve) / Rejected(실패, Reject) ]
function caller(resolve, reject) {
const produced = producing() // API 호출해줘, 이미지 가져와줘
if (succeeded) resolve(produced)
if (failed) reject(produced)
}
caller(
function resolve(produced) { consuming(produced) },
function reject(produced) { consuming(produced) },
)
new Promise((resolve, reject) => {
const result = getUserInformationAPI()
if (result.success) { resolve(result.user) }
if (result.failed) { reject({ type: 'No User', message: 'Error Occured' }) }
})
.then((user) => { console.log(user) })
.catch((error) => { console.log(error.message) })
Promise 객체를 생성할 때는 new 와 생성자 함수를 만들고 함수에 두개의 매개변수를 가진 콜백 함수를 만들어준다.
성공과 실패에 대한 처리는 .then()과 .catch()를 통해서 결과를 알려준다.
성공하면 .then()으로 가서 성공에 대한 추가 처리를 진행한다. 실패면 반대로 .catch()로 진행!!!
.finally()
프로미스가 이행되거나 거부될 때 상관없이 실행할 콜백 함수를 등록하고, 새로운 프로미스를 반환
새로 Promise 객체를 생성하는 것이 아닌 함수를 통해서 생성할 수도 있다.
// 프로미스 객체를 반환하는 함수 생성
function createPromise() {
return new Promise((resolve, reject) => {
// 비동기 작업을 시뮬레이션하기 위해 setTimeout 사용
const result = { success: true, user: { name: 'Magnus' }};
if (result.success) {
resolve(result.user);
}
if (result.failed) {
reject({ type: 'NoUser', message: 'Error Occurred' });
}
});
}
// 프로미스 객체를 반환하는 함수 호출
createPromise()
.then((user) => {
console.log(user);
})
.catch((error) => {
console.error(error.message);
});
함수 호출하면 프로미스 생성자를 return하여 프로미스 객체를 함수 반환값으로 얻어서 사용한다.
장점 : 재사용성(필요할 때마다 호출하여 사용 가능), 가독성(코드 구조 명확), 확장성(인자를 전달하여 동적으로 비동기 작업을 수행 가능.)

성공 케이스에서 반환된 new Promise 객체.
성공은 .then()으로

실패는 .catch()로

.catch() 로 잡아주지 않아서 실패 콜백이 정의되어 있지 않음.

new Promise로 프로미스 객체 생성하면, 비동기 작업을 시작하게 된다. 그러면 진행중, 성공, 실패 셋 중에 하나의 상태를 나타내게 된다.
이것이 프로미스 3가지 상태다.
아직 비동기 처리 로직이 완료되지 않은 상태다.
프로미스 객체의 상태가 Pending이 출력되는 경우다.
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("처리 완료")
}, 5000)
});
console.log(promise); // Promise {<Pending>}
resolve() 수행하게 되면 프로미스 성공을 알리는 개체를 호출하여 완료 상태가 된다.
위 예제에서라면 프로미스 코드를 실행하고 5초 동안 기다렸다가 다시 console.log()를 해보면 Fulfilled 상태가 된다.
Promise {<fulfilled>} 를 출력하게 된다.
resolve()가 아닌 reject()로 한다면 Promise {<rejected>} 를 출력.
.catch() 메서드를 호출하여 처리 실패에 대한 행동을 수행.
프로미스 핸들러인 .then(), .catch(), .finally() 를 연달아 연결하여 사용하는 것이다.
function add() {
return new Promise((resolve, reject) => {
resolve(100);
});
}
add()
.then((value1) => {
const data1 = value1 + 50;
return data1;
}) // 성공해서 150
.then((value2) => {
const data2 = value2 + 50;
return data2;
}) // 계속 성공해서 200
.then((value3) => {
const data3 = value3 + 50;
return data3;
}) // 250
.then((value4) => {
console.log(value4); // 250 출력
});
// 250 출력
.then()에서 값을 리턴하므로 반환값은 자동으로 프로미스 객체로 감싸져 반환하기 때문에 체이닝을 할 수 있다.
만약 예외 처리를 하고 싶다면 .then() 블록 안에 if문 작성해서 throw new Error('Error') 해서 사용하면 된다.
장점 : 여러 개의 비동기 작업을 순차적으로 수행할 수 있다.
한번에 한 값 사용하여 Promise Hell의 문제점을 해결 가능.
Promise.resolve()객체를 초기화하지 않고 생성하지도 않고 바로 사용할 수 있어서 간편하게 사용 가능하다.
기존에는 Promise 객체를 반환하는 함수를 만들어서 진행했었다. 그렇게 하지 않고 연관없는 함수인 getRandomNumber()를 할당한 const num을 Promise.resolve(num) 하고 반환하여 Promise 객체의 값을 처리하는 방식으로 하는 것이 Promise 정적 메서드다.
function getRandomNumber() {
const num = Math.floor(Math.random() * 10); // 0 ~ 9 사이의 정수
return num;
}
// Promise.resolve() 를 사용하여 프로미스 객체를 반환하는 함수
function getPromiseNumber() {
const num = getRandomNumber(); // 일반 값
return Promise.resolve(num); // 프로미스 객체
}
// 핸들러를 이용하여 프로미스 객체의 값을 처리하는 함수
getPromiseNumber()
.then((value) => {
console.log(`랜덤 숫자: ${value}`);
})
.catch((error) => {
console.error(error);
});
Promise.resolve()를 사용해서 정적 메서드로 한번에 호출 가능.
Promise.resolve() 를 사용하여 프로미스 객체와 전혀 연관없는 함수 내에서 필요에 따라 프로미스 객체를 반환하는 함수를 작성하여 사용할 수 있다.
당연히 resolve가 있었으니 Promise.reject()도 가능.
Promise.reject()
// 주어진 사유로 거부되는 프로미스 생성
const p = Promise.reject(new Error('error'));
console.log(p) // Promise { <rejected> Error: 'error' }
// 거부 사유를 출력
p.catch(error => console.error(error)); // Error: error
Promise.all()배열, Map, Set에 포함된 여러개의 프로미스 요소들을 한꺼번에 비동기 작업을 처리해야 할 때 유용하다.
모든 Promise 비동기 처리가 이행될 때까지 기다려서, 모든 Promise가 완료되면 그때 then 핸들러가 실행된다.
// 1. 서버 요청 API 프로미스 객체 생성 (fetch)
const api_1 = fetch("https://jsonplaceholder.typicode.com/users");
const api_2 = fetch("https://jsonplaceholder.typicode.com/users");
const api_3 = fetch("https://jsonplaceholder.typicode.com/users");
// 2. 프로미스 객체들을 묶어 배열로 구성
const promises = [api_1, api_2, api_3];
// 3. Promise.all() 메서드 인자로 프로미스 배열을 넣어, 모든 프로미스가 이행될 때까지 기다리고, 결과값을 출력
Promise.all(promises)
.then((results) => {
// results는 이행된 프로미스들의 값들을 담은 배열.
// results의 순서는 promises의 순서와 일치.
console.log(results); // [users1, users2, users3]
})
.catch((error) => {
// 어느 하나라도 프로미스가 거부되면 오류를 출력
console.error(error);
});
Promise.any()all()과는 반대로 모든 Promise 중 하나라도 완료되면 바로 반환한다.
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("promise1 failed");
}, 3000);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("promise2 succeeded");
}, 2000);
});
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("promise3 failed");
}, 1000);
});
// promise1, promise2, promise3은 각각 3초, 2초, 1초 후에 거부되거나 이행
Promise.any([promise1, promise2, promise3])
.then((value) => {
console.log(value); // "promise2 succeeded"
})
.catch((error) => {
console.error(error);
});
// 'promise2 succeeded'
// Promise2가 resolve이기 때문에 하나를 성공해서 바로 출력해버림.
Promise.any()는 가장 먼저 fulfilled(이행) 상태가 된 Promise만을 반환하거나, 혹은 전부 rejected(실패) 상태가 된 Promise(AggregateError)를 반환한다.
반면 Promise.race() 는 fulfilled(이행), rejected(실패) 여부 상관없이 무조건 처리가 끝난 프로미스 결과값을 반환한다.
쉽게 말하면 성공 실패 아무 상관없이 제일 먼저 수행이 끝난 Promise를 반환한다고 생각하면 된다.
Reference
🔗 MDN web docs - Promise 객체
🔗 https://velog.io/@bami/Javascript-Promise-%EA%B0%9D%EC%B2%B4 - Promise 객체
🔗 Promise 개념 & 문법 정복