프로미스를 사용하면 비동기 프로그래밍을 할 때 동기 프로그래밍 방식을 코드를 작성할 수 있다.
ES6에 프로미스가 추가되기 전에는 콜백(callback) 패턴을 많이 사용했었다. 하지만 콜백 패턴은 콜백이 조금만 중첩돼도 코드가 상당히 복잡해지는 단점이 있다.
function requestData1(callback) { //... callback(data); // 2 } function requestData2(callback) { //... callback(data); // 4 } function onSuccess1(data) { console.log(data); requestData2(onSuccess2); // 3 } function onSuccess1(data) { console.log(data); // 5 //... } requestData1(onSuccess1); // 1
콜백 패턴은 코드의 흐름이 순차적이지 않기 때문에 코드를 읽기 상당히 힘들다. 하지만 프로미스를 사용하면 코드가 순차적으로 실행되게 작성할 수 있다.
- 대기 중(pending) : 결과를 기다리는 중
- 이행됨(fulfilled) : 수행이 정상적으로 끝났고 결과값을 가지고 있음
- 거부됨(rejected) : 수행이 비정상적으로 끝났음
프로미스는 세 가지 상태 중 하나의 상태로 존재하고 이행됨, 거부됨 상태를 처리됨(settled) 상태라고 부른다. 프로미스는 처리됨 상태가 되면 더 이상 상태 변경이 되지 않는다.
const p = new Promise((resolve, reject) => { // ... // resoleve(data) // or reject('error message') });
new 키워드를 사용해서 프로미스를 생성한다. 생성된 프로미스의 초기 상태는 대기 중 상태이고 resolve와 reject라는 콜백 함수를 매개변수로 갖는다. 비동기 작업을 수행 후 성공했을 때 resolve를 호출하고, 실패했을 때 reject를 호출하면 된다. resolve를 호출하면 p 객체는 이행됨 상태가 되고 reject를 호출하면 거부됨 상태가 된다. new 키워드로 생성된 프로미스는 생성되는 순간 실행된다.
request() .then(data => { console.log(data); }) .catch(error => { console.log(error); });
then은 처리됨 상태가 된 프로미스를 처리할 때 사용되는 메서드이고 항상 프로미스를 반환하기 때문에 연속적으로 then 메서드를 호출할 수 있다.
catch는 프로미스 수행 중 발생한 예외를 처리하는 메서드이고 then과 마찬가지로 catch 메서드도 새로운 프로미스를 반환한다.
Promise.reject(10) .then(data => { console.log('then1:', data); return 20; }) .catch(error => { console.log('catch', error); return 30; }) .then(data => { console.log('then2', data); }); // catch: 10; // then2: 30
따라서 catch 메서드 이후에도 then 메서드를 사용할 수 있다.
finally는 프로미스가 이행됨, 거부됨 상태일 때 호출되는 메서드이다.
requestData() .then(data => { // ... }) .catch(error => { // ... }) .finally(data => { // ... });
finally 메서드는 프로미스 체인의 가장 마지막에 사용하면 되고 이전에 사용된 프로미스를 그대로 반환한다. 따라서 처리됨 상태인 프로미스의 데이터를 건드리지 않고 추가 작업을 할 때 사용될 수 있다.
Promise.all은 여러 개의 프로미스를 병렬 처리할 때 사용하는 함수이다.
Promise.all([requestData1(), requestData2()]).then(([data1, data2]) => { console.log(data1, data2); });
Promise.all 함수도 프로미스를 반환하는데 주의할 점은 입력된 모든 프로미스 중 하나라도 거부됨 상태가 된다면 Promise.all 함수가 반환하는 프로미스도 거부됨 상태가 된다.
Promise.rac는 여러 개의 프로미스 중에서 가장 빨리 처리된 프로미스를 반환하는 함수이다.
const promise1 = new Promise((resolve, reject) => { setTimeout(resolve, 500, 'one'); }); const promise2 = new Promise((resolve, reject) => { setTimeout(resolve, 100, 'two'); }); Promise.race([promise1, promise2]).then((value) => { console.log(value); // Both resolve, but promise2 is faster }); // expected output: "two"
Promise.race 함수에 입력된 프로미스 중에서 하나라도 처리됨 상태가 되면, Promise.race 함수가 반환하는 프로미스도 처리됨 상태가 된다.