[JavaScript] Callback, Promise
Callback
JavaScript에서, 다른 함수의 매개변수로 전달되어 특정 이벤트가 발생한 후 다시 호출되는 함수를 Callback(Callback 함수)이라고 한다.
console.log('1');
setTimeout(() => console.log('2'), 1000);
console.log('3');
-
위 코드를 실행해보면, 순서대로 '1', '3', '2' 가 출력된다. 코드가 순서대로 호출되긴 하지만, setTimeout에 의해 1초가 기다려지는 구문은 브라우저에게 '1초 후 이 함수를 다시 돌려줘'라고 요청을 하고, 다음 코드를 실행하게 되는 것이다. 이 때, setTimeout()의 매개변수로 전달된 화살표 함수 () => console.log('2')
가 Callback 함수이다.
-
Callback은 꼭 비동기 방식에서만 사용되는 것은 아니다.
Synchronous Callback
function printImmediately(print) {
print();
}
printImmediately(() => console.log('hello'));
Asynchronous Callback
function printWithDelay(print, timeout) {
setTimeout(print, timeout);
}
printWithDelay(() => console.log('async callback'), 2000);
Callback 지옥
Callback을 함수 내부에 계속해서 사용하게 될 경우, 코드의 가독성이 떨어지고 유지보수가 어려워진다는 단점이 있다. 흔히 이러한 경우를 Callback 지옥이라고 부른다.
class UserStorage {
loginUser(id, password, onSuccess, onError) {
setTimeout(() => {
if (
(id === 'nine' && password === 'dream') ||
(id === 'coder' && password === 'academy')
) {
onSuccess(id);
} else {
onError(new Error('not found'));
}
}, 2000);
}
getRoles(user, onSuccess, onError) {
setTimeout(() => {
if (user === 'nine') {
onSuccess({ name: 'nine', 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.getRoles(
user,
userWithRole => {
alert(
`hello ${userWithRole.name}, you are ${userWithRole.role}!`
);
},
error => {
console.log(error);
}
);
},
error => {
console.log(error);
}
);
- 위는 아주 간단한 코드이지만, Callback 함수가 계속해서 호출되므로써 가독성이 나빠지는 것을 확인할 수 있다.
Promise
위에서 살펴본 Callback의 단점을 보완하기 위한 방법으로, Promise가 있다. Promise에는 중요한 두 가지 요소가 있는데 State와 Producer/Consumer 이다.
- State: Promise의 상태를 나타낸다.
- pending: 대기 상태
- fullfilled: 성공
- rejected: 실패
- Producer/Consumer
- Producer: 데이터를 만드는 부분
- Consumer: 데이터를 사용하는 부분
Promise의 사용
// 1. Producer
// when new Promise is created, the executor runs automatically.
const promise = new Promise((resolve, reject) => {
// doing some heavy work (network, i/o files)
console.log('doing something....');
const id = prompt('insert id');
setTimeout(() => {
if (id === 'nine') {
resolve('nine');
} else {
reject(new Error('no network'));
}
}, 2000);
});
// 2. Consumers
// use 'then, catch, finally' for get result of resolve
// value는 promise가 정상적으로 실행되어서 resolve로 전달된 값
// 성공했다면 resolve, 실패하면 reject의 값을 전달받고
// 성공 시 then으로, 실패 시 catch로 값을 받는다.
// finally는 성공 실패 여부와 관계없이 무조건 한 번 실행된다.
promise
.finally(() => {
console.log('this is finally()');
})
.then(value => {
console.log(value);
})
.catch(error => {
console.log(error);
});
// 3. Promise chaining
const fetchNumber = new Promise((resolve, reject) => {
setTimeout(() => resolve(1), 1000);
});
fetchNumber
.then(number => number * 2)
.then(number => number * 3)
.then(number => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(number - 1), 1000);
});
})
.then(number => console.log(number));
// 4. Error Handling
const getHen = () =>
new Promise((resolve, reject) => {
setTimeout(() => resolve('🐔'), 1000);
});
const getEgg = hen =>
new Promise((resolve, reject) => {
// setTimeout(() => resolve(`${hen} => 🥚`), 1000);
setTimeout(() => reject(new Error(`error! ${hen} => 🥚`), 1000));
});
const cook = egg =>
new Promise((resolve, reject) => {
setTimeout(() => resolve(`${egg} => 🍳`), 1000);
});
getHen()
// .then(hen => getEgg(hen))
// 한가지만 받아서 전달하는 경우에는, 생략이 가능하다.
// 오류가 발생한 곳에 catch를 적절히 넣어, 다른 값으로 대체할 수 있다.
.then(getEgg)
.catch(error => {
return '🥖';
})
.then(cook)
.then(console.log);
Callback 예제를 Promise로 변환
위에서 살펴본 Callback의 예제를 Promise로 변환하면 아래와 같이 간단하게 바뀐 것을 볼 수 있다.
class UserStorage {
loginUser(id, password) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (
(id === 'nine' && password === 'dream') ||
(id === 'coder' && password === 'academy')
) {
resolve(id);
} else {
reject(new Error('not found'));
}
}, 2000);
});
}
getRoles(user) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (user === 'nine') {
resolve({ name: 'nine', 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(id => userStorage.getRoles(id))
.then(user => alert(`hello ${user.name}, you are ${user.role}!`))
.catch(console.log);
Author And Source
이 문제에 관하여([JavaScript] Callback, Promise), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://velog.io/@_nine/JavaScript-Callback-Promise
저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
JavaScript에서, 다른 함수의 매개변수로 전달되어 특정 이벤트가 발생한 후 다시 호출되는 함수를 Callback(Callback 함수)이라고 한다.
console.log('1');
setTimeout(() => console.log('2'), 1000);
console.log('3');
위 코드를 실행해보면, 순서대로 '1', '3', '2' 가 출력된다. 코드가 순서대로 호출되긴 하지만, setTimeout에 의해 1초가 기다려지는 구문은 브라우저에게 '1초 후 이 함수를 다시 돌려줘'라고 요청을 하고, 다음 코드를 실행하게 되는 것이다. 이 때, setTimeout()의 매개변수로 전달된 화살표 함수 () => console.log('2')
가 Callback 함수이다.
Callback은 꼭 비동기 방식에서만 사용되는 것은 아니다.
function printImmediately(print) {
print();
}
printImmediately(() => console.log('hello'));
function printWithDelay(print, timeout) {
setTimeout(print, timeout);
}
printWithDelay(() => console.log('async callback'), 2000);
Callback을 함수 내부에 계속해서 사용하게 될 경우, 코드의 가독성이 떨어지고 유지보수가 어려워진다는 단점이 있다. 흔히 이러한 경우를 Callback 지옥이라고 부른다.
class UserStorage {
loginUser(id, password, onSuccess, onError) {
setTimeout(() => {
if (
(id === 'nine' && password === 'dream') ||
(id === 'coder' && password === 'academy')
) {
onSuccess(id);
} else {
onError(new Error('not found'));
}
}, 2000);
}
getRoles(user, onSuccess, onError) {
setTimeout(() => {
if (user === 'nine') {
onSuccess({ name: 'nine', 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.getRoles(
user,
userWithRole => {
alert(
`hello ${userWithRole.name}, you are ${userWithRole.role}!`
);
},
error => {
console.log(error);
}
);
},
error => {
console.log(error);
}
);
위에서 살펴본 Callback의 단점을 보완하기 위한 방법으로, Promise가 있다. Promise에는 중요한 두 가지 요소가 있는데 State와 Producer/Consumer 이다.
- State: Promise의 상태를 나타낸다.
- pending: 대기 상태
- fullfilled: 성공
- rejected: 실패
- Producer/Consumer
- Producer: 데이터를 만드는 부분
- Consumer: 데이터를 사용하는 부분
Promise의 사용
// 1. Producer
// when new Promise is created, the executor runs automatically.
const promise = new Promise((resolve, reject) => {
// doing some heavy work (network, i/o files)
console.log('doing something....');
const id = prompt('insert id');
setTimeout(() => {
if (id === 'nine') {
resolve('nine');
} else {
reject(new Error('no network'));
}
}, 2000);
});
// 2. Consumers
// use 'then, catch, finally' for get result of resolve
// value는 promise가 정상적으로 실행되어서 resolve로 전달된 값
// 성공했다면 resolve, 실패하면 reject의 값을 전달받고
// 성공 시 then으로, 실패 시 catch로 값을 받는다.
// finally는 성공 실패 여부와 관계없이 무조건 한 번 실행된다.
promise
.finally(() => {
console.log('this is finally()');
})
.then(value => {
console.log(value);
})
.catch(error => {
console.log(error);
});
// 3. Promise chaining
const fetchNumber = new Promise((resolve, reject) => {
setTimeout(() => resolve(1), 1000);
});
fetchNumber
.then(number => number * 2)
.then(number => number * 3)
.then(number => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(number - 1), 1000);
});
})
.then(number => console.log(number));
// 4. Error Handling
const getHen = () =>
new Promise((resolve, reject) => {
setTimeout(() => resolve('🐔'), 1000);
});
const getEgg = hen =>
new Promise((resolve, reject) => {
// setTimeout(() => resolve(`${hen} => 🥚`), 1000);
setTimeout(() => reject(new Error(`error! ${hen} => 🥚`), 1000));
});
const cook = egg =>
new Promise((resolve, reject) => {
setTimeout(() => resolve(`${egg} => 🍳`), 1000);
});
getHen()
// .then(hen => getEgg(hen))
// 한가지만 받아서 전달하는 경우에는, 생략이 가능하다.
// 오류가 발생한 곳에 catch를 적절히 넣어, 다른 값으로 대체할 수 있다.
.then(getEgg)
.catch(error => {
return '🥖';
})
.then(cook)
.then(console.log);
Callback 예제를 Promise로 변환
위에서 살펴본 Callback의 예제를 Promise로 변환하면 아래와 같이 간단하게 바뀐 것을 볼 수 있다.
class UserStorage {
loginUser(id, password) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (
(id === 'nine' && password === 'dream') ||
(id === 'coder' && password === 'academy')
) {
resolve(id);
} else {
reject(new Error('not found'));
}
}, 2000);
});
}
getRoles(user) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (user === 'nine') {
resolve({ name: 'nine', 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(id => userStorage.getRoles(id))
.then(user => alert(`hello ${user.name}, you are ${user.role}!`))
.catch(console.log);
Author And Source
이 문제에 관하여([JavaScript] Callback, Promise), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://velog.io/@_nine/JavaScript-Callback-Promise
저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
위에서 살펴본 Callback의 예제를 Promise로 변환하면 아래와 같이 간단하게 바뀐 것을 볼 수 있다.
class UserStorage {
loginUser(id, password) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (
(id === 'nine' && password === 'dream') ||
(id === 'coder' && password === 'academy')
) {
resolve(id);
} else {
reject(new Error('not found'));
}
}, 2000);
});
}
getRoles(user) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (user === 'nine') {
resolve({ name: 'nine', 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(id => userStorage.getRoles(id))
.then(user => alert(`hello ${user.name}, you are ${user.role}!`))
.catch(console.log);
Author And Source
이 문제에 관하여([JavaScript] Callback, Promise), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@_nine/JavaScript-Callback-Promise저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)