Promise는 일단 class선언을 먼저해서 실행할 상태를 만들어 두고 필요할 때 callback해서 결과값을 나중에 받는다는 '약속'을 하는 것이다. 즉, 결과값은 실행이 완료된 후then이나catch메소드를 통해 받을 수 있다.promise는 비동기적 작업을 위한 자바스크립트의 객체로 비동기 처리 시 callback함수 대신에 사용된다.
여기서 '비동기 처리'란 특정 코드의 실행이 완료될 때까지 기다리지 않고 다음 코드를 먼저 수행하는 것을 의미한다.
Promise는 다음 중 하나의 상태를 가진다.
Promise 클래스를 생성하면 pending상태가 되며, 이 때 콜백함수를 선언할 수 있고 콜백함수의 인자는 resolve, reject이다.
new Promise((resolve, reject) => {
// network 통신, DB에서 file 읽어오기 등 heavy work 수행
});
Promise는 producer(정보제공)와 consumer(정보이용)의 두 가지로 구분된다고 볼 수 있다.
// 1. producer
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("amiee") // Promise가 정상적으로 수행
}, 2000); // 초는 ms단위
})
// 2. Consumer
promise
.then((value) => {
console.log(value);
})
.catch((error) => {
console.log(error);
})
.finally(() => {
console.log("finally");
});
then,catch,finallyPromise class에서 짜여진 로직에 따라 실행.
thenpromise가 제대로 수행되면then, 그리고 resolve를 통해 들어온 value return.catcherror핸들링. then에서 return된 promise를 catch가 다시 받음.finallyresolve, reject와 상관없이 사용.
Promise chaining은 결과가 .then의 chain을 통해 순차적으로 처리되는 것.
const fetchNumber = new Promise((resolve, reject) => {
setTimeout(() => resolve(1), 1000) // 1초 있다가 1 전달
})
fetchNumber
.then((num) => num*2) // num에 resolve의 인자인 1이 전달됨 => num = 1*2 = 2
.then((num) => num*3) // num에 위 .them에서 넘겨받은 인자 전달 => num = 2*3 = 6
.then((num) => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(num-1), 1000) // setTimeout은 resolve(5)를 1초 뒤 처리
});
})
.then((num) => console.log(num)); // 결과 5 (2초 소요)
const getHen = () =>
new Promise((resolve, reject) => {
setTimeout(() => resolve("🐔️"), 1000);
});
const getEgg = (hen) =>
new Promise((resolve, reject) => {
setTimeout(() => reject(new Error(`error! ${hen} => 🥚️`)), 1000); // 에러 발생하는 경우(reject)
});
const cook = (egg) =>
new Promise((resolve, reject) => {
setTimeout(() => resolve(`${egg} => 🍳️`), 1000);
});
getHen()
.then(getEgg) // 인자를 받아 동일한 값 출력하는 경우 생략가능 (getEgg) = ((hen) => getEgg(hen))
.catch((error) => {
// 계란을 받아올 때 에러가 생기는 경우 처리(중간에 발생하는 에러를 처리해서 요리가 끝까지 완성될 수 있도록 함)
return "🥖️";
})
.then(cook)
.then(console.log) // 여기도 생략 가능 (console.log) = ((meal) => console.log(meal))
.catch(console.log);
reference. 드림코딩 by 엘리(Youtube)
await, async를 사용하면 promise를 이용한 로직보다 좀 더 깔끔하게 작성할 수 있다.
// Promise를 이용한 비동기 로직
function fetchUser() {
return new Promise((resolve, reject) => resolve("Amiee"));
}
const user = fetchUser()
user.then(console.log) // 결과: Promise {'Amiee'}
console.log(user) // 결과: Amiee
// await
async function fetchUser() {
return "Amiee";
}
const user = fetchUser()
user.then(console.log) // 결과: Promise {'Amiee'} : async를 쓰면 promise를 쓰지 않아도 함수 내부에서 promise로 인식함.
console.log(user) // 결과: Amiee
function delay(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async function getApple() {
await delay(2000); // 2초가 지나면 resolve가 호출됨.
return "🍎️"; // 2초가 지날때까지 apple을 return해라
}
async function getBanana() {
await delay(1000);
return "🍌️";
}
async function pickFruits() {
const apple = await getApple();
const banana = await getBanana();
return `${apple} + ${banana}`;
}
pickFruits().then(console.log); // 결과: 🍎️ + 🍌️ (3초 뒤 출력)
Promise의 배열을 전달하게 되면 모든 Promise들이 병렬적으로 다 받을 때까지 모아준다.
function pickAllFruits() {
return Promise.all([getApple(), getBanana()])
.then(fruits) => fruits.join(" + "); // join: 배열을 string으로 모아주는 method
}
pickAllFruits().then(console.log) // 결과: 🍎️ + 🍌️
Promise의 race API 배열에 전달된 Promise 중 가장 먼저 전달된 promise만 return한다.
function pickOnlyOne() {
return Promise.race([getApple(), getBanana()]);
}
pickOnlyOne().then(console.log); // 결과: 🍌️ (1초)