javascript에서는 주로 비동기 프로그래밍을 사용하기 때문에 콜백 함수를 자주 사용합니다.
콜백함수가 중첩되어 사용되다 보면 코딩의 깊이가 깊어지고
각 콜백 함수 별 에러를 따로 처리해주어야하는 콜백 헬이 발생합니다.
하지만 ES2015부터 지원하는 Promise는 이러한 콜백 헬을 극복했다는 평가를 받고 있습니다.
■ Promise 사용법
- Promise 객체 생성
<script>
const condition = true;
const promise = new Promise((resolve, reject) => {
if (condition) {
resolve('성공');
} else {
reject('실패');
}
});
promise
.then((message) => {
console.log(message); // 성공(resolve)한 경우 실행
})
.catch((error) => {
console.error(error); // 실패(reject)한 경우 실행
});
</script>
new Promise로 프로미스를 생성하며 이렇게 생성된 promise변수에 then과 catch 매서드를 사용할 수 있습니다.
프로미스 내부에서 resolve가 호출되면 then이 reject가 호출되면 catch가 실행되며
resolve와 reject에 넣어준 인자를 then과 catch의 매개변수에서 받을 수 있습니다.
위 코드의 실행 결과는 콘설에 '성공' 이 출력되며 condition 변수를 false로 변경하면 '실패' 메세지가 에러로 출력됩니다.
- Promise 중첩
<script>
promise
.then((message) => {
return new Promise((resolve, reject) => {
resolve(message);
});
})
.then((message2) => {
console.log(message2);
return new Promise((resolve, reject) => {
resolve(message2);
});
})
.then((message3) => {
console.log(message3);
})
.catch((error) => {
console.error(error);
});
</script>
처음 then에서 Promise 객체를 리턴하게 되면 다음 then에서 받을 수 있습니다.
여기서 다시 message2를 resolve했으므로 다음 then에서 message3로 받았습니다.
이러한 특성을 활용하여 콜백을 프로미스로 바꿀 수 있습니다.
■ 콜백 -> 프로미스 변경
<script>
function findAndSaveUser(Users) {
Users.findOne({}, (err, user) => {
if (err) {
return console.error(err);
}
user.name = 'zero';
user.save((err) => {
if (err) {
return console.error(err);
}
Users.findOne({ gender: 'm'}, (err, user) => {
// 생략
});
});
});
}
</script>
콜백 함수가 3번 중첩되어있는 전형적인 콜백 함수를 사용하는 패턴입니다. 이를 프로미스 형식으로 변경해보겠습니다.
<script>
function findeAndSaveUser(Users) {
Users.findOne({})
.then((user) => {
user.name = 'zero';
return user.save();
})
.then((user) => {
return Users.findOne({ gender: 'm'});
})
.then((user) => {
// 생략
})
.catch((err) => {
console.error(err);
});
}
</script>
변경 된 코드는 then 메서드 들이 순차적으로 실행되는 모습을 보입니다.
또한, 각 콜백 함수별 따로 처리해주었던 에러가 마지막 catch에서 한번에 처리되는 것을 볼 수 있습니다.
모든 함수를 위와 같이 프로미스형식으로 변경 할 수 있는것은 아닙니다.
findOne과 save 매서드가 내부적으로 프로미스 방식을 지원하기 때문에 가능한 것입니다.
하지만 이는 util이라는 내장 모듈의 promisify 매서드를 통해 콜백 패턴을 프로미스 패턴으로 바꿔줄 수 있습니다.
참고 : 길벗출판사 - Node.js 교과서(조현영 지음)