Promise

Promise란 무엇인가


Promise란 자바스크립트 비동기 처리에 사용되는 객체이다. 비동기 처리란, 특정 코드의 실행이 완료될 때까지 기다리지 않고, 다음 코드를 먼저 수행하는 자바스크립트의 특성을 말한다.


Promise를 사용하는 이유


자바스크립트는 비동기 처리를 위해 콜백 함수를 사용하였다. 그러나, 콜백 패턴은 처리 순서를 보장하기 위해 콜백 함수가 계속해서 중첩(nesting)되어 복잡도가 높아지는 콜백 헬이 발생하는 문제가 있다. 즉, 가독성이 좋지가 않게 된다. 이 문제를 해결하기 위해 ES6에서는 Promise를 사용한다.


Promise 사용 방법



Promise 생성

Promise는 Promise 생성자 함수를 이용해 인스턴스, 즉 Promise 객체를 반환한다. Promise 생성자 함수는 비동기 작업을 수행할 콜백 함수를 인자로 전달 받는다. 이 콜백 함수는 resolve 함수와 reject 함수이다.

1
2
3
4
5
6
7
8
9
10
const promise = new Promise((resolve, reject) => {
// 비동기 작업을 수행

if (/* 비동기 작업 수행 성공 */) {
resolve('result'); // resolve 함수 호출
}
else { /* 비동기 작업 수행 실패 */
reject('failure'); // reject 함수 호출
}
});


Promise 실행

1
2
3
promise
.then(result => console.log(result))
.catch(error -> console.log(error))


Promise 상태

  • pending: 비동기 처리가 아직 수행되지 않은 상태(resolve 또는 reject 함수가 아직 호출되지 않은 상태)
  • fulfilled: 비동기 처리가 성공적으로 수행된 상태(resolve 함수가 호출된 상태)
  • rejected: 비동기 처리가 실패된 상태(reject 함수가 호출된 상태)


Promise 기본 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
const promise1 = function(param) {
return new Promise(function(resolve, reject) {
if(param) {
resolve("success") // "success"가 then 메소드의 result의 값으로 전달됨
} else {
reject("fail") // "fail"이 catch 메소드의 error의 값으로 전달됨
}
})
}

promise1(true)
.then(result => console.log(result))
.catch(error => console.log(error))

비동기 처리에 성공하면, resolve 함수가 호출되고, 이때 resolve 함수의 인자로 비동기 처리 결과를 전달한다. 이 처리 결과는 Promise 객체의 후속 처리 메소드로 전달된다.
비동기 처리에 실패하면, reject 함수가 호출되고, 이때 reject 함수의 인자로 에러 메시지를 전달한다. 이 에러 메시지는 Promise 객체의 후속 처리 메소드로 전달된다.


Promise 처리 흐름


How Promise Works

출처: Promise 처리 흐름


Promise 코드 예제


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function getData() {
return new Promise(function (resolve, reject) {
api.get('https://naver.com/users/1', function (response) {
if (response) {
resolve(response);
}
reject(new Error("Request failure"));
});
});
}

getData().then(function (data) {
console.log(data); // response 값 출력(resolve 함수의 인자로 받아온 response가 data로 받아옴)
}).catch(function (err) {
console.error(err); // Error 출력
});


Promise 체이닝(Chainning)


Promise는 후속 처리 메소드를 체이닝(chainning)하여 여러 개의 프로미스를 연결하여 사용할 수 있기 때문에, 콜백 헬을 해결한다. Promise 객체를 반환한 비동기 함수는 프로미스 후속 처리 메소드인 then이나 catch 메소드를 사용할 수 있다. 따라서 then 메소드가 Promise 객체를 반환하도록 하면 여러 개의 프로미스를 연결하여 사용할 수 있다.

1
2
3
4
get(`${url}/1`)
.then(result1 => document.getElementById('app').innerHTML = result1)
.then(result2 => document.getElementById('result').innerHTML = result2)
.catch(error => console.log(error));


Promise.all


Promise는 주로 생성자 함수(new Promise)로 사용되지만, 메소드도 가지고 있다. 그 중, Promise.all 메소드는 여러개의 비동기 작업들이 존재하고, 이 비동기 작업들이 모두 완료되었을 때 작업을 진행하고 싶을 때 사용한다.

Promise.all 메소드는 프로미스가 담겨 있는 배열 등의 이터러블을 인자로 전달 받고, 이 모든 프로미스들은 병렬로 처리 되고, 그 처리 결과를 resolve하는 새로운 프로미스를 반환한다.

1
2
3
4
5
6
Promise.all([
new Promise(resolve => setTimeout(() => resolve(10), 3000)), // 10
new Promise(resolve => setTimeout(() => resolve(20), 2000)), // 20
new Promise(resolve => setTimeout(() => resolve(30), 1000)) // 30
]).then(console.log) // [ 10, 20, 30 ]
.catch(console.log);

Promise.all 메소드는 전달받은 모든 Promise를 병렬로 처리한다. 모든 Promise의 처리가 완료될 때까지 기다린 후에 모든 처리 결과를 resolve 또는 reject한다.

Promise.all 메소드는 처리 순서가 보장되기 때문에, 나중에 있는 Promise가 먼저 처리되더라도, 반환되는 Promise의 배열안에는 순서대로 반환된다.

1
2
3
4
5
6
Promise.all([
new Promise((resolve, reject) => setTimeout(() => reject(new Error('Error 1!')), 8000)),
new Promise((resolve, reject) => setTimeout(() => reject(new Error('Error 2!')), 1000)),
new Promise((resolve, reject) => setTimeout(() => reject(new Error('Error 3!')), 5000))
]).then(console.log)
.catch(console.log); // Error: Error 2!

Promise 처리가 하나라도 실패하면, 가장 먼저 실패한 Promise가 reject한 error를 reject하는 새로운 Promise를 반환한다.