콜백
#콜백
파라미터로 함수를 전달받아, 함수의 내부에서 실행하는 함수이다.
#콜백의 장단점
콜백함수를 사용하면서 얻는 이점은 다음과 같다.
- 함수를 인자로 받기 때문에 필요에 따라 함수의 정의를 달리해 전달할 수 있다.
- 함수를 굳이 정의하지 않고 익명 함수로도 전달 가능하다.
- 비동기(Asynchronous) 처리 방식의 문제점을 해결할 수 있다.
하지만 콜백함수를 사용하면 다음과 같은 단점이 있다.
- 콜백함수를 너무 남용하면 코드의 가독성이 떨어진다. (콜백 지옥)
- 에러 처리가 어렵다.
#동기콜백과 비동콜백
아래는 코드 예시
//동기콜백
function printImmediately(print){
print()
}
printImmediately(() => console.log('hello'));
//비동기콜백
function pringWithDelay(print, timeout){
setTimeout(print,timeout )
}
pringWithDelay(()=>console.log('async callback'),2000)
여기서 보면 동기와 비동기의 큰차이점은 동기 같은경우는 함수자체가 주도권을 가지고 실행이 된다고 하면 비동기 같은경우는 함수에서 setTimeout이라는 거에 위탁(?)을 해서 주도권을 넘겨주고 실행이 된다는점? 이라고 느껴진다.
#콜백지옥의 예시
// 콜백지옥
class UserStorage{
loginUser(id,password,onSuccess,onError){
setTimeout(()=>{
if(
(id === 'jin' && password === 'hwan')||
(id === 'kim' && password === 'bocal')
){
onSuccess(id);
}else{
onError(new Error('not found'));
}
},2000);
}
getRoles(user, onSuccess, onError){
setTimeout(()=>{
if(user === 'jin'){
onSuccess({name:'jin',role:'admin'})
}else{
onError(new Error('no access'))
}
},1000)
}
}
//1. id와 pass 받아오기
//2. login
//3. 역할받기
//4. 이름과 역할 받기
const UuserStorage = new UserStorage();
const id = prompt('아이디를 입력해주세요');
const password = prompt('비밀번호를 입력해주세요');
UserStorage.loginUser(
id,
password,
user => {
UserStorage.getRoles(
user,
userWithRole =>{
alert(`Hello ${userWithRole.name}, you hava 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 === 'jin' && password === 'hwan')||
(id === 'kim' && password === 'bocal')
){
resolve(id);
}else{
reject(new Error('not found'))
}
},2000);
});
}
getRoles(user){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
if(user === 'jin'){
resolve({name:'jin',role:'admin'})
}else{
reject(new Error('no access'))
}
},1000)
})
}
}
//1. id와 pass 받아오기
//2. login
// 3. 역할받기
// 4. 이름과 역할 받기
const userStorage = new UserStorage();
const id = prompt('아이디를 입력해주세요');
const password = prompt('비밀번호를 입력해주세요');
userStorage
.loginUser(id,password)
.then(userStorage.getRoles)
.then(user => alert(`Hello ${user.name}, you hava a ${user.role} role`))
.catch(console.log)
위와 다른점은 프라미스를 이용해서 데이터를 받는쪽인 밑부분이 간결해졋고 위에 불필요한 onSuccess,onError 사라져서 콜백 에 콜백을 부르는게 사라진게 보인다는거? 코드를 영상보면서 적었지만 아직 해석이 힘들다는점....ㅠㅠ 다시봐야겟다...
#마지막 여담
아직 익숙하지 않는거라서 그런지 막상 다른거에 접목해서 사용하려고 하면 본코드를 보면서 아 이건 이렇게 해야되지 아 저건 저렇게 해야되지 하며 코드 진행을 하게 된다는게 아직은 슬프다.
처음쓰는거다보니까 그런거겟지 라는 생각은 하는데 조급한 나의 마음은 ... ㅠㅠ
이거 이용해서 쓴게 아래 코드~
function delay(ms) {
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(ms)
},3000)
})
}
delay()
.then(ms => alert('3초후 실행'))
그냥 프로미스로 지연코드 만드는거였는데 살짝 햇깔렷지만 결국 성공 ㅋㅋㅋ 다행이라고 생각한다.
자주쓰다보면 익숙해지겠지... 후...