콜백(Callback Hell)의 문제를 해결하기 위해 여러 라이브러리들이 등장했고 많은 개발자들에게 선택받은 것이 바로 Promise
패턴을 사용한 라이브러리들입니다. 이 라이브리러들은 표준화되어서 결국 ES2015에 이르러 Javascript 언어 자체에 포함되었습니다.
Promise
는 '언젠간 끝나는 작업' 의 결과 값을 담는 통과 같은 객체입니다. Promise
객체가 만들어지는 시점에는 그 통 안에 무엇이 들어갈지 모를 수 있습니다. 대신 then
메서드를 통해 Callback을 등록해서 작업이 끝났을 떄 결과값을 가지고 추가 작업을 할 수 있습니다.
Promise
객체를 생성하는 가장 쉬운 방법은 Promise.resolve
정적 메소드를 사용하는 것입니다.
const p = Promise.resolve(1);
위 코드에서 1
이라는 결과 값을 가지는 Promise
객체를 생성했습니다. 그러나 이 코드는 비동기 작업을 하고 있지 않습니다.
비동기 작업을 하는 Promise
객체는 Promise
생성자를 통해 만들 수 있습니다.
const p = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('2초가 지났습니다.');
resolve('hello');
}, 2000);
});
Promise
생성자는 콜백을 인수로 받습니다. 이 콜백의 첫 번째 인수로 resolve
함수가 들어오는데 콜백 안에서 resolve
를 호출한 다는 것은 resolve
에 인수로 준 값이 곧 Promise
객체의 궁극적인 결과값이 됩니다.
두 번째 인수로 들어오는 reject
함수는 비동기 작업에서 에러가 발생했을 때 호출하는 함수입니다.
위 예제에서는 setTimeout
을 이용해 2초가 지난 뒤에 콜백이 실행 되도록 했습니다. 즉, p
변수에 저장된 Promise
객체는 2초동안 결과값이 없는 상태였다가, 2초 뒤에 resolve
함수가 호출되어 p
객체는 결과값을 갖는 객체가 됩니다.
Promise
객체의 결과값을 사용해 추가 작업을 하기 위해선, then
메서드를 호출해야 합니다. then
메서드에 콜백을 넘겨서, 첫 번째 인수로 들어온 결과값을 가지고 추가 작업을 할 수 있습니다.
p.then(msg => {
console.log(msg); // Hello
});
then
메서드의 중요한 특징 중 하나는 바로 then
메서드 자체도 Promise
객체를 반환한다는 것입니다. 이 때 콜백에서 반환한 값이 곧 Promise
의 결과값이 됩니다.
const p2 = p.then(msg => {
return msg + ' world';
});
p2.then(msg => {
console.log(msg); // Hello world
});
위 코드는 아래와 같이 줄여 쓸 수 있습니다.
p.then(msg => {
return msg + ' world';
}).then(msg => {
console.log(msg);
});
또한 then
메서드에 넘겨준 콜백에서 Promise
객체를 반환하면, then
메서드가 반환한 Promise
객체는 앞의 Promise
객체의 결과를 따르게 됩니다.
아래 코드의 실행결과는 다음과 같습니다.
// Promise 객체를 반환하는 함수
function delay(ms) {
return new Promise(resolve => {
setTimeout(() => {
console.log(`${ms} 밀리초가 지났습니다.`);
resolve();
}, ms);
});
}
delay(1000)
.then(() => delay(2000))
.then(() => Promise.resolve('끝'))
.then(console.log);
console.log('시작');
시작
1000 밀리초가 지났습니다.
2000 밀리초가 지났습니다.
끝