자바스크립트 Promise를 사용하는 비동기 패턴은 여러 종류가 있지만, 아래의 패턴이 가장 깔끔한 것 같다. 다음 step으로 값을 넘기고 싶을땐 resolve(값), error 핸들링을 할 땐 reject(에러)를 하면 된다. resolve나 reject를 하는 것은 또 다른 promise 객체를 return하는 것이기 때문에 chaining이 가능하다.
function asyncTask(message, callback) {
setTimeout(() => {
console.log(message);
if (typeof callback === 'function') {
callback();
}
}, 3000);
}
const step1 = () => new Promise((resolve, reject) => {
asyncTask('step1에서 호출한 비동기작업 완료.', () => {
resolve();
});
});
const step2 = () => new Promise((resolve) => {
asyncTask('step2에서 호출한 비동기작업 완료.', () => {
resolve('step2 result value');
});
});
const step3 = value => new Promise((resolve) => {
setTimeout(() => {
asyncTask('step3에서 호출한 비동기작업 완료.', () => {
console.log(`step2에서 resolve한 값: ${value}`);
resolve('step2 result value');
});
}, 1000);
});
const onError = (error) => {
console.log(error);
};
step1()
.then(step2)
.then(step3)
.catch(onError);
Promise.all은 비동기 작업을 병렬로 처리하고 싶을 때 사용하면 된다. 2초가 걸리는 step1과 4초가 걸리는 step2가 동시에 시작되며, 2초 뒤 step1이 끝나더라도 step2가 끝날 때 까지 기다린 뒤 step2가 완료되면 각 return 값을 배열로 반환한다.
const step1 = new Promise((resolve, reject) => {
console.log('step1 started');
setTimeout(() => {
resolve('step1 ended');
}, 2000);
});
const step2 = new Promise((resolve, reject) => {
console.log('step2 started');
setTimeout(() => {
resolve('step2 ended');
}, 4000);
});
Promise.all([step1, step2])
.then((result) => {
console.log(result); // result -> ["step1 ended", "step2 ended"]
})
Promise.race는 step1과 step2가 동시에 시작되며 2초 뒤 step1이 완료되면 step1의 return 값만 반환하며 끝난다. 어떤 경우에 유용하게 써먹을 지는 좀 더 생각해 봐야겠다.
const step1 = new Promise((resolve, reject) => {
console.log('step1 started');
setTimeout(() => {
resolve('step1 ended');
}, 2000);
});
const step2 = new Promise((resolve, reject) => {
console.log('step2 started');
setTimeout(() => {
resolve('step2 ended');
}, 4000);
});
Promise.race([step1, step2])
.then((result) => {
console.log(result); // 먼저 끝나는 작업인 step1이 resolve 된다.
});