[JavaScript] 프라미스(promise) 객체
비동기 작업을 위한 패턴으로 이행에 성공했을 때와 실패했을 때의 동작을 미리 약속하는 것.
이 때 동작은 콜백함수로 이루어지며 성공했을 시 resolve, 실패했을 시 reject로 실행된다.
new Promise() 생성자 함수로 프라미스 객체를 생성하면 그와 동시에 콜백함수가 호출되는데
이 때 전달되는 함수는 executor(실행자, 실행 함수)라고 한다.
resolve, reject는 자바스크립트가 제공하는 자체 콜백 함수로
함수의 이행 결과에 따라 resolve 혹은 reject 중 하나의 값은 무조건 호출된다.
new Promise가 생성하는 promise 객체의 내부 프로퍼티.
state
- 기본값 'pending(대기 상태)'
- resolve 호출 시 fulfilled(이행 상태)
- reject 호출 시 rejected(실패 상태)
result
- 기본값 'undefined'
- resolve 호출 시 value 전달.
- reject 호출 시 error 전달.
<작성 방법>
let promise = new Promise(resolve, reject)
resolve(); //성공시 불러 올 콜백함수
reject(); //실패시 불러 올 콜백함수
<resolve 예제>
<script>
let promise = new Promise((resolve, reject) => {
// setTimeout은 executor로 new Promise 생성 시 즉각 호출.
setTimeout(() => resolve(`${console.log("이행합니다.")}`), 1000);
});
// resolve의 value인 console.log가 1초후 콘솔창에 출력.
</script>
<reject 예제>
<script>
let promise = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error("에러 객체 호출")), 1000)
});
// reject의 error인 new Error가 1초후 콘솔창에 출력.
</script>
이렇게 promise 객체가 실행을 끝내면 처리된 promise가 되며 변경된 상태는 더 이상 변하지 않는다.
즉, resolve든 reject든 둘 중 하나의 상태는 무조건 호출 되며 resolve가 호출됐으면 reject로 재변경은 이루어지지 않음.
그래서 resolve가 호출이 되는 executor 이후에 작성된 reject 실행문은 무시된다.
<script>
let promise = new Promise((resolve, reject) => {
resolve(alert("실행되면 promise객체는 처리된 상태가 된다."));
// executor가 즉각 실행되고 resolve로 처리된 promise 객체 상태가 된다.
reject(new Error("한 번 처리된 promise 객체의 상태는 변하지 않는다.")); //무시
});
</script>
위 예제에서는 처리 결과를 확인할 수 있게 alert, console.log 등으로 확인했지만
promise 객체는 처리된 상태를 지니게 됐을 뿐 어딘가에서 호출해서 사용한 상태는 아니다.
console.log(promise)
// Promise라는 객체를 반환할 뿐. value를 반환하지는 않는다.
상태가 처리된 promise를 사용하는 메서드는 아래와 같다.
then, catch, finally
then
then은 promise 객체의 가장 기본적인 메서드로 작성 순서에 따라 각 상태에 대한 executor를 인수로 받는다.
<script>
let promise = new Promise((resolve, reject) => {
resolve(".then의 첫 번째 줄에 매개변수로 전달된다.");
// executor가 즉각 실행되고 resolve로 처리된 promise 객체 상태가 된다.
reject(new Error(".then의 두 번째 줄에 매개변수로 전달된다.")); //무시
});
promise.then(
(result) => alert(result), // result에 인수로 전달된 resolve의 value가 alert된다.
(reject) => alert(reject)
);
</script>
첫 번째 줄에 작성된 함수의 매개변수에는 resolve의 value가 인수로 전달되고,
두 번째 줄에 작성된 함수의 매개변수에는 reject의 error가 인수로 전달된다.
각 줄은 쉼표(,)로 구분하며 성공의 경우만 다루고 싶다면 인수를 하나만 작성하면 된다.
<script>
let promise = new Promise((resolve, reject) => {
resolve("성공의 경우만 생각합니다.");
});
promise.then((result) => alert(result)); // 성공의 경우만 생각합니다.
</script>
catch
반대로 에러의 경우만 다루고 싶다면 .then에서 첫 번째 인수에 null을 전달하면 되는데, 이는 .catch를 작성하는 것과 같다.
<script>
let promise = new Promise((resolve, reject) => {
reject(new Error("실패만 다룹니다."));
});
promise.then(null, (rejected) => {
alert(rejected);
});
//-------------------------------------------------
let promise = new Promise((resolve, reject) => {
reject(new Error("실패만 다룹니다."));
});
promise.catch(rejected => alert(rejected))
</script>
finally
try..catch문의 finally와 마찬가지로 promise의 처리 상태와 상관 없이 처리가 끝나면 항상 실행된다.
매개변수가 없으며 promise의 처리 상태도 확인할 수 없기 때문에 promise의 처리가 끝났는 지 등을 알리는보편적인 동작을 수행할 때 사용하기 좋다.
<script>
let promise = new Promise((resolve, reject) => {
resolve("fulfilled 상태로 처리되었습니다.");
});
promise
.finally(() => {
alert("promise가 처리되었습니다.");
})
.then((resolve) => alert(resolve));
</script>
<예제>
<body>
<script>
let boo = true;
// promise 객체 생성
// new Promise(resolve, reject);
const coffee = new Promise((res, rej) => {
boo ? res('커피 주문') : rej('주문 실패');
});
// promise 객체 사용 (promise체이닝)
// coffee
// .then(good => console.log(good))
// .catch(bad => console.log(bad));
coffee.then(
good => console.log(good), // 성공 시 실행되는 함수 (첫번 째 인수)
bad => console.log(bad) // 실패 시 실행되는 함수 (두번 째 인수)
);
</script>
</body>