드림코딩 유튜브 채녈의 의 자바스크립트 강의를 보고 공부한 내용입니다!
출처 :
https://www.youtube.com/watch?v=s1vpVCrT8f4
https://www.youtube.com/watch?v=JB_yU6Oe2eE&t=676s
이번엔 비동기처리의 시작! 힘을 조금만 개방해서 callback과 promise를 살펴봅시다.
크큭, 아직 뒤에 알아야 할게 많이 남았으니, 50%만 발휘해라 닝겐들! 비동기 처리는 아주 어마무시하다!
callback 함수는 다른 함수의 인자로써 이용되거나, 이벤트로 불러지는 함수를 말합니다. 이 콜백 함수는 비동기 처리를 가장 쉽게 할 수 있는 방법이긴 하지만, 그다지 추천하지는 않는 방법인가 봅니다. 자칫하면 콜백 지옥에 빠질수 있어서 그렇다는데요.
먼저 콜백 지옥 코드를 보면서, 콜백함수가 뭔지 봅시다.
// 1. userStorage
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);
}
// 2. getRoles
getRoles(user, onSuccess, onError) {
setTimeout(() => {
if (user === 'ellie') {
onSuccess({ name: 'ellie', role: 'admin' });
} else {
onError(new Error('no access'));
}
}, 1000);
}
}
// 3. 로그인
const userStorage = new UserStorage();
const id = prompt('enter your id');
const password = prompt('enter your passrod');
// 4. 로그인 기능
userStorage.loginUser(
id,
password,
user => {
userStorage.getRoles(
user,
userWithRole => {
alert(
`Hello ${userWithRole.name}, you have a ${userWithRole.role} role`
);
},
error => {
console.log(error);
}
);
},
error => {
console.log(error);
}
);
1. userStorage는 클래스입니다. 두 개의 함수로 이루어져 있습니다. 첫 번 째로 인자 네개(id, password, onSuccess, onError)를 받는 loginUser에 setTimeout을 적용해서 2초 뒤에 실행합니다.
2. getRoles 클래스는 인자 세개(user, onSuccess, onError)를 받아서 setTimeout을 적용해 1초 뒤에 실행합니다. 이때 getRoles는 loginUser에서 onSuccess와 onError를 받아와야합니다. 이걸 콜백 함수라고 합니다.
3. 로그인을 위해 클래스를 선언하고 프롬프트를 사용해 아이디와 비밀번호를 불러옵니다. html 파일을 연결시켜 실행시키면
아이디와 비밀번호를 입력할 수 있는 프롬프트 창이 상단에 뜹니다.
아이디는 ellie, 비밀번호는 dream으로 입력하면! 잠시 뒤에 알림 창으로
이렇게 admin role을 받았다고 알림을 줍니다. 1과 2에 setTimeout으로 비동기처리가 되었기때문에, 3이 먼저 실행됩니다. 이 부분이 4. 로그인 기능 부분입니다.
4. 로그인 기능 부분에서는 login user와 getRoles를 사용해 user에게 특정 역할을 부여합니다. getRoles는 user, onSuccess, onError 세가지 인자를 받습니다. user는 user 그대로, 성공한 상태이니 userWithRole이 되어 알림창으로 어떤 역할을 받았는지 알려주고, 마지막으로 에러 상태는 에러로 표시하도록 합니다.
이렇게 함수가 함수끼리 맞물리도록 해서 함수가 다른 함수를 받아서 쓰도록 만든 것이 callback입니다. 사람들 되게 똑똑해...
callback으로는 간편하게 비동기 처리를 할 수 있습니다! 하지만 단점이 아주 분명한데요. 코드가 길어질수록 가독성이 떨어지고, 전체 구조를 살피기가 힘들어진다는 단점입니다.
그래서! 콜백 지옥이라는 말이 생겼습니다. 위의 코드가 콜백 지옥의 맛보기 코드라고 하는데요. 정말 구조를 파악하기가 어렵긴 합니다. 갑자기 user는 어떻게 생긴 것이며, userWithRole은 어떻게 만들어지는 것이며... 한눈에 파악하기 힘들고 가독성이 떨어지는 코드가 되어버린 것이죠. 코드를 좀더 간결하게 만들기 위해 등장한 것이 바로 promise 입니다.
promise는 이미지 한 장으로 간결하게 설명할 수 있습니다.
영어로 되어있지만 간단합니다! 더 간단한 그림도 있습니다! 그래도 공식사이트나 다름없는 모질라에서 가져온 그림이니까 천천히 살펴보면, 먼저 promise 객체를 생성하면, fulfill인지, reject인지 판단한 다음, .then으로 갑니다. 이때 reject로 거절된 상태라면 .then에서 에러가 발생합니다. 에러 처리를 해주지 않으면 그대로 에러가 나지만, 에러 핸들링을 해주면 .catch가 실행되는 구조입니다!
뒤에 promise가 또 등장하는건 promise chaining을 위해서입니다. .then .catch는 특정 value를 return 해주는데, 그 value가 다시 promise가 될 수 있습니다. 그러면 이 promise는 다시 또 fulfilled 인지 reject인지에 따라 특정 값을 리턴하거나 하고 또 이작업이 반복되고... 꼬리에 꼬리를 물 수 있습니다.
위에서 콜백 지옥에 대해 이야기했는데... 제가 아직 코딩 응애지만 이 chaining도 길어지면 callback 못지 않을거란 생각이 듭니다... 어쨌든 콜백 지옥을 면하기 위해 promise가 등장했다고 하니, 위의 코드를 promise로 깨끗하게 만들어 볼까요 ?
class UserStorage {
// 1.
loginUser(id, password) {
return new promise((resolve, reject) => {
if (
(id === 'ellie' && password === 'dream') ||
(id === 'coder' && password === 'academy')
) {
resolve(id);
} else {
reject(new Error('not found'));
}
setTimeout(() => {
}, 2000);
})
}
// 2.
getRoles(user) {
return new promise((resolve, reject) => {
setTimeout(() => {
if (user === 'ellie') {
resolve({ name: 'ellie', role: 'admin' });
} else {
reject(new Error('no access'));
}
}, 1000);
})
}
}
// 3.
const userStorage = new UserStorage();
const id = prompt('enter your id');
const password = prompt('enter your passrod');
// 4.
userStorage.loginUser(id, password)
.then(user => userStorage.getRoles)
.then(user => alert(
`Hello ${user.name}, you have a ${user.role} role`
))
.catch(console.log)
와! 깔끔 그잡채! 코드의 가독성이 매우 올라갔습니다. 특히 위의 코드에서는 4. 부분이었던 로그인 기능 부분이 매우 깔끔해 진것을 볼 수 있습니다. 에러 처리까지 다 했음에도 깔-끔한 코드입니다.
세세하게 살펴보면
1. classUserStorage 에서 loginUser는 promise를 생성하고 if문을 사용해 로그인한 상태의 유저를 만듭니다. 이 promise는 reslove(fulfilled)일때는 id를, reject일때는 에러를 value로 줍니다.
2. getRoles는 유저를 인자로 받아 프로미스를 생성하는데, user가 ellie가 맞으면, fulilled(resolve)가 되어서 admin role를 줍니다. reject면 마찬가지로 에러를 줍니다.
3. 클래스를 선언하고, 프롬프트창을 띄워줍니다. 비동기처리 때문에 1과 2는 순서가 앞이지만 먼저 실행되지 않고, 프롬프트 창 부터 뜹니다. 1과 2는 webAPI에 있다가 지정해둔 타이머가 끝나고 나면 큐로 가겠죠?
4. 이제 promise가 주는 value인 user를 .then이나 .catch가 받아온 후, .then인지, .catch인지에 따라 맞는 결과를 만들어줍니다! .then으로 getRoles를 주고, 또 통과해서 그 다음의 .then이 되면 alert으로 알려줍니다!
끝!
뭔가 설명이 부족해보이지만 정말입니다. 이렇게 설명이 부족해보일정도로 복잡했던 코드를 단번에 정리해버리는 promise! 최고짱짱~
하지만 promise보다 더 업그레이드 된 게 있다고 하는데 ... 그건 다음시간에... 계속...
2023.04.04 - [백엔드/javaScript] - [Js] 비동기 처리 [1] 비동기 처리를 알아보자!(setTimeout)
2023.04.06 - [백엔드/javaScript] - [Js] 비동기 처리 [3] async/await를 알아보자!
[Js] 비동기 처리 [3] async/await를 알아보자! (0) | 2023.04.06 |
---|---|
[Js] 비동기 처리 [1] 비동기 처리를 알아보자!(setTimeout) (0) | 2023.04.04 |