프로미스
자바스크립트와 노드에서 주로 비동기를 접합니다. 특히, 이벤트 리스너를 사용할 때 콜백 함수를 자주 사용합니다.
프로미스는 다음과 같은 규칙이 있습니다. 먼저 프로미스 객체를 생성해야 합니다.
const condition = true; // true이면 resolve, false면 reject
const promise = new Promise((resolve, reject) => {
if (condition) {
resolve('성공');
}
else {
reject('실패');
}
});
// 다른 코드가 들어갈 수 있음
promise
.then((message) => {
console.log(message); // 성공(resolve)한 경우 실행
})
.catch((error) => {
console.error(error); // 실패(reject)한 경우 실행
})
.finally(() => { // 끝나고 무조건 실행
console.log('무조건');
});
new Promise로 프로미스를 생성할 수 있으며, 그 내부에 resolve와 reject를 매개변수를 갖는 콜백 함수를 넣습니다. 이렇게 만든 promise 변수에 then과 catch 메서드를 붙일 수 있습니다. 프로미스 내부에서 resolve가 호출되면 then이 실행되고, reject가 호출되면 catch가 실행됩니다. finally 부분은 성공/실패 여부와 상관없이 실행됩니다.
resolve와 reject에 넣어준 인수는 각각 then과 catch의 매개변수에서 받을 수 있습니다.
프로미스를 쉽게 설명하자면, 실행은 바로 하되 결괏겂은 나중에 받는 객체입니다. 결과값은 실행이 완료된 후 then이나 catch 메소드를 통해 받습니다. new Promise는 바로 실행되지만, 결과값은 then을 붙였을 때 받게 됩니다.
then이나 catch에서 다시 다른 then이나 catch를 붙일 수 있습니다. 이전 then의 return 값을 다음 then의 매개변수로 넘깁니다. 프로미스를 return한 경우에는 프로미스가 수행된 후 다음 then이나 catch가 호출됩니다.
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);
});
이것을 활용해서 콜백을 프로미스로 바꿀 수 있습니다. 다음은 콜백을 쓰는 패턴 중 하나입니다. 이를 프로미스로 바꿔보겠습니다.
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);
}
User.findOne({ gender: 'm' }, (err, user) => { // 세 번째 콜백
// 생략
});
});
});
}
각 콜백 함수마다 에러도 따로 처리해줘야 합니다. 코드를 다음과 같이 바꿀 수 있습니다.
fuction findAndSaveUser(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);
});
}
프로미스 여러 개를 한 번에 실행할 수 있는 방법이 있습니다. 기존의 콜백 패턴이었다면 콜백을 여러번 중첩해서 사용해야 할 것입니다. 하지만 Promise.all을 활용하면 간단히 할 수 있습니다.
const promise1 = Promise.resolve('성공1');
const promise2 = Promise.resolve('성공2');
Promise.all([promise1, promise2])
.then((result) => {
console.log(result); // ['성공1', '성공2'];
})
.catch((error) => {
console.error(error);
});
프로미스가 여러 개 있을 때 Promise.all에 넣으면 모두 resolve 될 때까지 기다렸더가 then으로 넘어갑니다. result 매개변수에 각각의 프로미스 결괏값이 배열로 들어 있습니다. Promise 중 하나라고 reject사 되면 catch로 넘어갑니다.