// js 에서 비동기를 간편하게 처리할 수 있도록 도와주는 obj
// 정해진 장시간의 기능을 수행하고 나서 정상적으로 수행되었다면 성공의 메세지와 함께 처리의 결과값을
// 전달해 준다. 만약 실패했다면, error 를 전달해 준다.
// 사전예약 느낌이랄까
'use strict'
// Promise is a js object for asynchronous operation.
// state: pending(작업이 수행중일 때) -> fulfilled (성공적 상태) or rejected state ( 실패 )
// Producer vs Consumer
// 1. Producer
// when new Promise is created, the executor(callback func) runs automatically.
// 원하지 않아도 만들어지는 순간 바로 네트워크와 통신을 시작하기 때문에 이를 유의해야 한다.
const promise = new Promise((resolve, reject) => {
// doing some heavy work (network, read filed) ... 왜?
// 네트워크에서 큰 데이터를 받아오거나, 파일에서 무언가 큰 데이터를 읽어는 과정은 무겁다.
// 이런 것을 동기화 방식으로 처리하면 작업들을 처리할 때 다음 라인 코드가 실행되지 않는다.
// 따라서 무거운 작업들을 비동기적으로 처리한다.
console.log('doing something...');
setTimeout(()=> {
resolve('ellie'); // 성공적으로 끝내고 resolve 통해서 전달
//reject(new Error('no networt'));
} , 2000);
});
// 2. Consumers: then, catch, finally
// then : promise 가 정상적으로 잘 수행되어서 resolve 라는 callback func 를 통해서 전달한
// 값, 여기서는 위의 'ellie' 가 전달 되어서 온다.
// then 만 있으면 성공적인 case 만 다룬 것이라서 위에서 reject 했을 때의 경우
// uncaught Type error가 뜬다. 그러니 catch도 만들어보자.
promise
.then(value => {
console.log(value);
})
.catch(error => {
console.log(error); // error, 즉 위의 reject 에서 보낸 no network 가 출력된다.
})
.finally(() => {
console.log('finally'); // 실패 했든 성공 했든 마지막에 실행된다.
});
// 3. Promise chaining
const fetchNumber = new Promise((resolve, reject) => {
setTimeout(() => resolve(1), 1000);
});
fetchNumber
.then(num => num * 2)
.then(num => num * 3)
.then(num => {
return new Promise((resolve, reject) => {
setTimeout(()=> resolve(num - 1), 1000);
});
})
.then(num => console.log(num));
// 4. Error Handling
const getHen = () =>
new Promise((resolve, reject) => {
setTimeout(() => resolve('🥠'), 1000);
});
const getEgg = hen =>
new Promise((resolve, reject) => {
setTimeout(() => reject(new Error(`error! ${hen} => 🍻`)), 1000);
});
const cook = egg =>
new Promise((resolve, reject) => {
setTimeout(() => resolve(`${egg} => 🥚`), 1000);
});
// getHen()
// .then(hen => getEgg(hen))
// .then(egg => cook(egg))
// .then(meal => console.log(meal));
//위와 같은 코드는 다음과 같이 줄일 수 있다.
getHen()
.then(getEgg) // 바로 getegg 에 암묵적으로 전달 해 준다.
.catch(error => { // 위의 then 에서 egg를 받아오는데 실패 했다면, 다른 재료를 넘겨주기 위함이다. error handling
return '🍕';
})
.then(cook)
.then(console.log)
.catch(console.log); // reject 될 시에 catch 한다. Error: error! 🥠 => 🍻 at promise.js:66
const f1 = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("1번 주문 완료");
}, 1000);
});
};
const f2 = (message) => {
console.log(message);
return new Promise((res, rej) => {
setTimeout(() => {
res("2번 주문 완료");
}, 2000);
});
};
const f3 = (message) => {
console.log(message);
return new Promise((res, rej) => {
setTimeout(() => {
res("3번 주문 완료");
}, 3000);
});
};
f1()
.then((res) => f2(res))
.then((res) => f3(res))
.then((res) => console.log(res))
.catch(console.log)
.finally(() => {
console.log("끝");
}); // 이 경우 6초가 있어야 작업이 끝난다. 줄일수 없을까?
//아래 코드는 3초가 걸린다. 다만, 위의 코드는 하나씩 결과물을 차례대로 보여주지만, Promise.all 은 한번에 다 보여준다.
//그렇기 때문에 하나라도 제대로 받아오지 못하면 아예 보여주지 못한다. 다 보여주거나 안보여주거 할 때 사용한다.
console.time("x");
Promise.all([f1(), f2(), f3()]).then((res) => {
console.log(res);
console.timeEnd("x");
});
// race. 말 그대로 경주다. 하나라도 1등으로 완료되면 끝난다.
Promise.race([f1(), f2(), f3()]).then((res) => {
console.log(res); //1번 주문 완료
});
// 1번이 끝나고 2번에서 reject 를 return 해 주고 있지만 더 이상 진행되지 않는다. 1번에서 끝난것이다.
//위 코드는 다음 async 에서 개선 될 것이다.
callback to promise