프로미스는 비동기 상태를 값으로 다룰 수 있는 객체다.
프로미스를 사용하면 비동기 프로그래밍을 할 때 동기 프로그래밍 방식으로 코드를 작성할 수 있다.
콜백패턴의 문제
자바스크립트에서는 비동기 프로그래밍의 한 가지 방식으로 콜백 패턴을 많이 사용했었다.
그러나 콜백 패턴은 콜백이 조금만 중첩돼도 코드가 상당히 복잡해지는 단점이 있다.
콜백 패턴은 코드의 흐름이 순차적이지 않기에 코드를 읽기가 상당히 어렵다. 그러나!! 프로미스를 사용하면 코드가 순차적으로 실행되게 작성할 수 있다.
requestData1()
.then(data =>{
console.log(data);
return requestData2();
})
.then (data =>{
console.log(data);
// ...
});
프로미스의 3가지 상태
대기중(pending): 결과를 기다리는 중
이행됨 (fullfilled): 수행이 정상적으로 끝났고 결과값을 가지고 있음
거부됨(rejected): 수행이 비정상적으로 끝났음
프로미스를 생성하는 법
const p1= new Promise((resolve,reject)=>{
//...'
//resolve(data)
//or reject('error message')
});
const p2=Promise.reject('error message');
new키워드를 사용하지 않고 Promise.reject를 호출하면 거부됨 상태인 프로미스가 생성된다.
const p3=Promise.resolve(param);
Promise.resolve를 호출해도 프로미스가 생성된다.
일반적으로 new 키워드를 사용해서 프로미스를 생성한다. 이 방법으로 생성된 프로미스는 pending(대기중)상태가 된다. 생성자에 입력되는 함수는 resolve,reject라는 콜백함수를 매개변수로 받는다.
비동기로 어떤 작업을 수행 후 성공했을 때 resolve를 호출하고, 실패했을 때 reject를 호출하면 된다.
프로미스 이용하기 1:then
then
은 처리됨 상태가 된 프로미스를 처리할 때 사용되는 메서드다. 프로미스가 처리됨 상태가 되면 then메서드의 인수로 전달된 함수가 호출된다.
requestData().then(onResolve,onReject);
Promise.resolve(123).then(data=>console.log(data));//123
Promise.reject('err').then(null,error=>console.log(error));//에러발생
프로미스가 처리됨 상태가 되면 onResolve함수가 호출되고 거부됨 상태가 되면 onReject함수가 호출된다.
then메서드는 항상 프로미스를 반환한다. 따라서 하나의 프로미스로부터 연속적으로 then메서드를 호출할 수 있다.
연속적으로 then메서드 호출
requestData1()
.then(data =>{
console.log(data);
return requestData2();
})
.then(data=>{
return data+1;
//만약 프로미스가 아닌 값을 반환하면 then메서드는 이행됨 상태인 프로미스를 반환
})
.then(data=>{
throw new Error('some error');
//onResolve 또는 onReject함수 내부에서 예외가 발생하면 then 메서드는 거부됨 상태인 프로미스를 반환한다.
})
.then(null,error=>{
console.log(error);
});
onResolve,onReject함수에서 프로미스를 반환하면 then 메서드는 그 값을 그대로 반환한다.
결과적으로 then 메서드는 항상 프로미스를 반환한다.
프로미스가 거부됨 상태인 경우에는 onReject함수가 존재하는 then을 만날 때까지 이동한다.
프로미스 사용시 주의할 점
1) return키워드 깜빡하지 않기
then 메서드 내부 함수에서 return 키워드를 입력하는 것을 깜빡하기 쉽다.
then메서드가 반환하는 프로미스 객체의 데이터는 내부 함수가 반환한 값. return키워드를 사용하지 않으면 프로미스 객체의 데이터는 undefined가 된다.
Promise.resolve(10)
.then(data =>{
console.log(data);
Promise.resolve(20);//여기서 return 키워드를 입력하면 의도한 대로 20 출력
})
.then(data =>{
console.log(data);//undefined가 출력된다.
});
2)프로미스는 불변객체다
function requestData() {
const p=Promise.resolve(10);
p.then(()=>{
return 20;
});
return p;
}
requestData().then(v=>{
console.log(v);//10=>2번
});
then메서드는 기존 객체를 수정하지 않고 새로운 프로미스를 반환한다.
2번 코드에서 20이 출력되길 원한다면 requestData함수를 다음과 같이 수정해야 한다.
function requestData(){
return Promise.resolve(10).then(v=>{
return 20;
});
}
3)프로미스를 중첩해서 사용하지 않기
requestData1().then(result1 =>{
requestData2(result1).then(result2=>{
//...
});
});
중첩된 코드를 아래와 같이 리팩토링 할 수 있다.
requestData1()
.then(result1=>{
return requestData2(result1);
})
.then(result2=>{
//...
});