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
,finally
Promise class에서 짜여진 로직에 따라 실행.
then
promise가 제대로 수행되면then
, 그리고 resolve를 통해 들어온 value return.catch
error핸들링. then에서 return된 promise를 catch가 다시 받음.finally
resolve, 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초)