[Node.js] 03 - Promise
프로미스에 대해 시작하기 앞서 프로미스나인 영상을 시청하겠다.
https://youtu.be/8uOBj0pINT8?si=PUE1LcmvKD0vgObJ
잘 시청했길 바란다.
프로미스(Promise)
프로미스는 비동기 작업의 최종 완료 또는 실패를 나타내는 객체다.
✅ new Promise(): 작업의 최종 완료 또는 실패에 관한 메시지를 반환
- resolve(성공 리턴 값): 작업 성공 시 호출될 callback 함수
- reject(실패 리턴 값): 실패 시 호출될 callback 함수
✅ .then()
- Promise 정상 수행 후 실행
- resolve를 통해서 전달한 값이 매개변수로 전달됨
✅ .catch()
- 오류 발생 시 실행
- reject를 통해 전달한 값이 매개변수로 전달됨
✅ .finally()
- 성공, 실패 모든 경우에 실행
// 1. Promise generate
const promise = new Promise ( (resolve, reject) => {
console.log('reading file...');
setTimeout(()=> {
let read = true;
if (read) {
resolve('file read success!');
} else {
reject(new Error('File read fail.'));
}
}, 2000);
});
// 2. then, catch, finally
promise
.then(value => {
console.log(value);
})
.catch(error => {
console.log(error);
})
.finally(()=> {
console.log('finally');
});
✅ Promise Chaining
- then 안에서 return한 값이 다음 then으로 전달된다.
- return 값이 프로미스면 resolve 후 전달
- 에러 발생은 catch에서 한 번에 처리
// 3. Promise chainging
const fetchData = new Promise( (resolve, reject)=> {
setTimeout(()=> resolve('Carrot', 1000));
});
fetchData
.then(data => data + ' Cheese')
.then(data => data + ' Cake')
.then(data => {
return new Promise( (resolve, reject)=> {
setTimeout(()=>resolve(data+'!'),1000);
});
})
.then(data => console.log(data))
.catch(error => {
console.log(error);
});
// 출력 결과 >> Carrot Cheese Cake !
✅ Callback hell에 대한 해결책이다.
- 콜백 헬이란 여러 개의 중첩된 콜백이 비동기 작업을 처리하는 데 사용되어 코드가 깊게 중첩되고 읽기 어려운 상황을 뜻한다.
- 먼저 Callback hell이 발생하는 상황을 보겠다.
- 아래 코드는 두 개 이상의 비동기 작업과 중첩된 콜백 함수를 순차적으로 실행하는 코드다.
function loginUser(id, password, callback) {
setTimeout(() => {
console.log('사용자 정보 얻음');
const user = { userId: id };
callback(user);
}, 3000);
}
function getUserMovies(id, callback) {
setTimeout(() => {
callback(['Titanic', 'Home Alone', 'AVATAR']);
}, 2000);
}
function movieDetails(movie, callback) {
setTimeout(() => {
callback('영화 제목은 ...');
}, 2000);
}
const user = loginUser('msjwa', 215, user => {
console.log(`${user.userId}님 환영합니다.`);
getUserMovies(user.userId, (movies) => {
console.log(movies);
movieDetails(movies[0], title => {
console.log(title);
});
});
});
이런 비동기 작업과 중첩 콜백이 여러 개가 추가되면 추가될수록 코드를 이해하고 유지 관리하기가 점점 더 어려워질 것이다. 이를 방지하기 위한 해결책이 바로 프로미스다. 위 코드를 프로미스로 수정해 보겠다.
function loginUser(id, password) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('사용자 정보 얻음');
const user = { userId: id };
resolve(user);
}, 3000);
});
}
function getUserMovies(id) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(['Titanic', 'Home Alone', 'AVATAR']);
}, 2000);
});
}
function movieDetails(movie) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('영화 제목은 ...');
}, 2000);
});
}
loginUser('msjwa', 215)
.then(user => {
console.log(`${user.userId}님 환영합니다.`);
return getUserMovies(user.userId);
})
.then(movies => {
console.log(movies);
return movieDetails(movies[0]);
})
.then(title => {
console.log(title);
})
.catch(error => {
console.error(error);
});
이와 같이 수정하게 되면 코드의 흐름을 잘 따라갈 수 있어 유지보수하는 데 큰 도움이 될 것이다. 다음에는 이런 프로미스 기반 코드를 좀 더 쓰기 쉽고 읽기 쉽게 하고, 비동기 코드를 동기식으로 작성할 수 있는 async/await에 대해 공부해 보겠다.