// callback으로 비동기 만들기
class UserStorage {
loginUser(id, password, onSuccess, onError){
setTimeout(() => {
if(
(id === 'hyo' && password === '0416') ||
(id === 'woo' && password === '0715')
){
onSuccess(id);
}
else {
onError(new Error('not found'))
}
}, 5000)
}
getRoles(user, onSuccess, onError){
setTimeout(() => {
if(user === 'hyo'){
onSuccess({name: 'hyo', role: 'admin'});
}
else {
onError(new Error('no access'));
}
}, 1000);
}
}
//
const userLogin = new UserStorage();
const id = prompt('id를 입력하시오');
const password = prompt('password를 입력하라');
userLogin.loginUser(
id,
password,
(user) => {
userLogin.getRoles(user,
(userInfo) => {
alert(`Hello ${userInfo.name}님 반가워요`)
}
),
(error) => {
alert('Error')
}
},
(error) => {
alert('error')
}
)
실행을 시키면 alert()함수를 썻기에 바로 입력창이 뜨며
id로 'hyo', password로 '0416'을 누르니 콘솔창에 'Hello Hyo님 반가워요'라고 잘 뜨는걸 확인할 수 있다.
// 1. Producer
const promise = new Promise((resolve, reject) => { // Promise(re,re) -> resolve,reject 라는 executor라는 콜백함수 인자 2개가 존재
console.log('doing something...')
setTimeout(() => {
// resolve('hyo');
reject(new Error('not found'))
}, 1000)
})
// Promise 함수는 선언만 해도 바로 실행됨 -> 만약 버튼을 눌렀을때
// 실행시키고 싶을땐 주의해서 사용해야함!
// 아래 A 함수는 실행안됨.
const A = () => {
console.log('hi')
}
// 2. Consumers
promise.then((value) => {
console.log(value); // .붙여가며 체이닝가능
}).catch((err) => { // 실패했을때
console.log(err);
})
.finally(() => { // 요즘 나온 함수인데 finally를 쓰면 성공하든 실패하든 마지막에 호출됨!
console.log('finally')
})
// 3. Promise chaining
const fetchNumber = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1)
reject('not found')
}, 1000)
});
fetchNumber.then(num => num * 2)
.then(num => num + 5)
.then(num => {
return new Promise((resolve, reject) => { // 또 다른 비동기인 Promise를 써도되는구나!
setTimeout(() => {
resolve(num - 2);
}, 1000)
}).then(num => num + 5)
})
.then((num) => {
console.log(num + 10);
}) // 계속해서 체이닝 가능!
// 4. Error Handling
const getBaby = () =>
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Baby')
}, 1000)
})
const getChild = (baby) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
// resolve(baby + ' => Child')
reject(new Error(baby + ' => Child'));
}, 1000)
})
}
const getAdult = (child) =>
new Promise((resolve, reject) => {
setTimeout(() => {
resolve(child + ' => Adult');
}, 1000)
})
getBaby()
.then(baby => getChild(baby)) // 콜백함수 안에서 인자가 그대로 다른 함수의 인자로 들어갈때 간결하게 쓸수 있음 -> then(getChild)
.catch(err => {
return 'baby2';
})
.then(child => getAdult(child)) // then(getAdult)
.then(v => console.log(v)) // then(console.log)
.catch()
class UserStorage {
loginUser(id, password){
return new Promise((resolve, reject) => {
setTimeout(() => {
if(
(id === 'hyo' && password === '0416') ||
(id === 'woo' && password === '0715')
){
resolve(id)
}
else {
reject(new Error('not found'))
}
}, 5000)
})
}
getRoles(user){
return new Promise((resolve, reject) => {
setTimeout(() => {
if(user === 'hyo'){
resolve({name: 'hyo', role: 'admin'});
}
else {
reject(new Error('no access'));
}
}, 1000);
})
}
}
//
const userLogin = new UserStorage();
const id = prompt('id를 입력하시오');
const password = prompt('password를 입력하라');
userLogin.loginUser(id, password)
.then(userLogin.getRoles)
.then(v => console.log(v.name + '님 반가워요!'));
// -------------- Async - Await --------------
// async await는 promise를 조금 더 간결하고 그리고 동기적으로
// 실행되는것 처럼 보이게 만들어주는 녀석이다!
// promise 에서 .then().then().then ... 이런 난잡한 promise 위에
// 조금 더 간편한 async await API 를 사용하면
// 우리가 동기식으로 순서대로 작성하는 것처럼 간편하게 작성할 수 있게 도와준다.
// 1. async
// function fetUser() {
// return new Promise((resolve,reject) => {
// resolve('hi')
// })
// }
// 위의 promise처럼 써도되지만 아래의 async 를 넣고 promise를 쓰지않아도
// 결과값은 Promise {fulfilled 상태!}
// async 라는 키워드를 쓰면 자동으로 코드블럭이 Promise 로 바뀜!
async function fetUser() {
return 'hi';
}
const user = fetUser();
console.log(user);
// 2. await
// await이라는 키워드는 async가 붙은 함수 안에서만 쓸수 있다.
function delay(ms) {
return new Promise(resolve => setTimeout(resolve,ms));
}
async function getHi() {
await delay(3000); // delay(3000)이 끝날때까지 기다려!
return 'Hi' // 위의 await 키워드 함수가 끝나면 리턴!
}
// 위 async함수를 promise 함수로 만들어 보면 ->
function getHiPro() {
return delay(3000)
.then(() => 'Hi2')
}
async function getBye() {
await delay(3000);
return 'Bye';
}
// then 지옥!! 으로 써본다.
function concatWords() {
return getHi()
.then(h => {
return getBye().then(b => `${h} && ${b}`)
})
}
concatWords().then(console.log)
// 위의 then지옥 말고 async 키워드를 써서 간결하고 동기적으로 보이는것 처럼 만들어본다.
async function concatWords2() {
const hi = await getHi();
const bye = await getBye();
return hi + bye;
}
concatWords2().then(console.log)
// 하지만 위에서 getHi()에서 3초기다렸다가 또 getBye()에서 3초기다리고
// return hi + bye를 실행하는건 비효율적이다
// getHi()와 getBye()는 서로 기다릴필요가없으므로
// 더럽게 쓰지만 한번 써본다.
async function concatWords3() {
const hiPromise = getHi(); // 기다릴필요없이 getHi()를 실행시킨값을 hiPromise에 할당
const byePromise = getBye(); // 기다릴필요없이 ~~
const hi = await hiPromise; // hiPromise를 받아올때까지 기다려!
const bye = await byePromise; // byePromise를 받아올때까지 기다려!
return `${hi} ${bye} ~~`
}
concatWords3().then(console.log)
// 하지만 위처럼 더럽게 쓰지않는다!
// 유용한 Promise APIs 가 있다!
// Promise.all()
function concatWords4() {
return Promise.all([getHi(), getBye()]) // 모든 Promise들이 병렬적으로 다 받을때까지 모아주는 녀석이다!
.then(v => v.join(' + ')) // 위의 애들이 다 받아지면 다 받아진 배열이 다시 전달이된다! ['hi','bye']로!
}
concatWords4().then(console.log)
// 만약 가장 먼저 처음으로 받아오는 데이터만 출력 하고 싶을때 쓰는
// Promise API 를 알아보자!
// Promise.race()
function concatWords5() {
return Promise.race([getHi(),getBye()]) // 얘는 Promise.all() 처럼 배열의 형태로 받아오지 않아 join안써도되기도하고 쓸수가 없다고 뜬다!
}
concatWords5().then(console.log)