13.Promise 콜백지옥을 무찌르자
1. Promise 란 무엇일까?
Javascript에서 제공하는 비동기를 간편하게 처리할수 있도록 도와주는 object이다.
2. Promise의 두가지 포인트
첫번째, state(상태)
-
Process가 무거운 operation(처리)를 하고 있는중인지, 기능 수행을 성공했는지 실패했는지 state(상태)에 대해서 이해하는것이 중요하다.
-
operation이 수행중일때는 : pending 상태
-
operation이 성공적으로 마칠때는 : fullfilled 상태
-
operation에서 문제가 발생할때는(파일을 찾을수 없거나 , 네트워크에서 문제가 발생) : rejected 상태
-
두번째, producer 와 consumer의 차이점
-
producer : 우리가 원하는 데이터를 제공하는 사람
-
consumer : 제공된 데이터를 사용하는 사람
3. Promise 만들기
Producer
- Promise 는 resolve아 reject라는 콜백함수를 받는 executer(실행자)라는 콜백함수를 전달해줘야한다.
const promise = new Promise((resolve, reject) => {
//doing some heavy work(network, read files 는 비동기적으로 처리하는것이 좋다. 왜?? 오래걸리기 때문에 동기적으로 하면 다른일을 하지 못함)
console.log("doing something");
setTimeout(() => {
resolve("ellie"); //성공적으로 network or readfiles를 햇다면 resolve()함수를 사용한다.
reject(new Error("no network"));
//만약 성공적으로 받아오지 못했다면 밑에reject()함수가 실행되어 그 이유를 나타내준다.
}, 2000);
});
꿀팁
- promise가 만들어지게 되면 , 자동적으로 실행해버린다. 따라서 버튼을 눌러서 어떠한 network나 readfiles를 하기위해서는 이렇게 작성해서는 안된다.
Consumers : then, catch, finally
promise
.then((value) => {
console.log(value); //ellie
})
.catch((error) => {
console.log(error); // no network
}) //error를 잡기위함
.finally(() => {
console.log("final");
});
-
성공했을때 결과값 : doingSomething , ellie , final
-
실패했을때 결과값 : doingSomething , no network , final
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));
- 이러게 Promise를 한번더 비동기화하여 전달할수 있다.
4. Error chaining(연결하기)
const getHen = () => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve("닭"), 1000);
});
};
const getEgg = (hen) => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(`${hen}=>달걀`), 1000);
});
};
const cook = (egg) => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(`${egg}=>병아리`), 1000);
});
};
getHen()
.then((hen) => getEgg(hen))
.then((egg) => cook(egg))
.then((meal) => console.log(meal));
// same code
// getHen()
// .then(getEgg)
// .then(cook)
// .then(console.log);
- 결과값 : 닭=>달걀=>병아리
4. Error chaining (2) , 에러가 발생했을때
const getHen = () => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve("닭"), 1000);
});
};
const getEgg = (hen) => {
return new Promise((resolve, reject) => {
setTimeout(() => reject(new Error(`error! ${hen}=>"달걀"`)), 1000);
});
};
const cook = (egg) => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(`${egg}=>병아리`), 1000);
});
};
getHen()
.then((hen) => getEgg(hen))
.catch((error) => {
return "빵";
})
.then((egg) => cook(egg))
.then(console.log)
.catch(console.log);
- getEgg()에서 발생한 에러를 다른것인 “빵”으로 대처하기 위해
.then((hen) => getEgg(hen))
.catch((error) => {
return "빵";
})
을 쓴거다.
5. Callback Hell Example을 해결하는 방법
- 기존
class UserStorage {
loginUser(id, password, onSuccess, onError) {
setTimeout(() => {
if (
(id === "ellie" && password == "dream") ||
(id === "coder" && password === "academy")
) {
onSuccess(id);
} else {
onError(new Error("not found"));
}
}, 2000);
}
getRoles(user, onSuccess, onError) {
setTimeout(() => {
if (user === "ellie") {
onSuccess({ name: "ellie", role: "admin" });
} else {
onError(new Error("no access"));
}
}, 1000);
}
}
const userStorage = new UserStorage();
const id = prompt("enter your id");
const password = prompt("enter your password");
userStorage.loginUser(
id,
password,
(user) => {
userStorage.getRolesuser(
user,
(userWithRole) => {
alert(
`Hello" ${userWithRole.name}, you have a ${userWithRole.role} role`
);
},
(error) => {
console.log(error);
}
);
},
(error) => {
console.log(error);
}
);
- 바뀐 후
class UserStorage {
loginUser(id, password) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (
(id === "ellie" && password == "dream") ||
(id === "coder" && password === "academy")
) {
resolve(id);
} else {
reject(new Error("not found"));
}
}, 2000);
});
}
getRoles(user, onSuccess, onError) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (user === "ellie") {
resolve({ name: "ellie", role: "admin" });
} else {
reject(new Error("no access"));
}
}, 1000);
});
}
}
const userStorage = new UserStorage();
const id = prompt("enter your id");
const password = prompt("enter your password");
userStorage
.loginUser(id, password)
.then((user) => alert(`Hello" ${user.name}, you have a ${user.role} role`))
.catch(console.log);
Leave a comment