Promise는 자바스크립트에서 비동기적인 작업을 처리하기 위한 객체입니다. 비동기적인 작업은 주로 서버와의 데이터 통신, 파일 로딩 등이 해당됩니다. Promise 객체는 비동기 작업이 완료되었을 때 처리할 수 있는 값을 제공하며, 비동기 작업의 성공 또는 실패를 감지하고 관리하는데 사용됩니다.
먼저 Promise의 간단한 문법을 보겠습니다.
let promise = new Promise(function(resolve, reject) {
// executor
});
new Promise에 전달되는 함수는 *executor(실행자, 실행 함수)*라고 부릅니다.
resolve와 reject는 자바스크립트에서 자체 제공하는 콜백입니다. 개발자는 resolve와 reject를 신경 쓰지 않고 executor 안 코드만 작성하면 됩니다.
executor에선 결과를 즉시 얻든 늦게 얻든 상관없이 상황에 따라 인수로 넘겨준 콜백 중 하나( resolve, reject )를 반드시 호출해야 합니다.
따라서 executor는 아래 그림과 같이 promise의 상태를 둘 중 하나로 변화시킵니다.
💡 Promise의 상태
1. pending: initial state, neither fulfilled nor rejected.
2. fulfilled: meaning that the operation completed successfully.
3. rejected: meaning that the operation failed.
pending의 상태는 fulfilled가 될수도 있고 rejected가 될수도 있다.
❗️프라미스는 성공 또는 실패만 합니다.
executor는 resolve나 reject 중 하나를 반드시 호출해야 합니다. 이때 변경된 상태는 더 이상 변하지 않습니다. 한마디로, resolve나 reject가 호출되면 그 이후는 무시됩니다.
let promise = new Promise(function(resolve, reject) {
resolve("완료");
reject(new Error("…")); // 무시됨
setTimeout(() => resolve("…")); // 무시됨
});
then, catch, finally
.then, .catch, .finally 메서드를 사용해 promise를 객체를 다룰 수 있습니다.
1. then.
.then의 첫 번째 인수는 프라미스가 이행되었을 때 실행되는 함수이고, 여기서 실행 결과를 받습니다.
.then의 두 번째 인수는 프라미스가 거부되었을 때 실행되는 함수이고, 여기서 에러를 받습니다.
let promise = new Promise(function(resolve, reject) {
setTimeout(() => resolve("완료!"), 1000);
});
// resolve 함수는 .then의 첫 번째 함수(인수)를 실행합니다.
promise.then(
result => alert(result), // 1초 후 "완료!"를 출력
error => alert(error) // 실행되지 않음
);
반대로 프라미스가 거부된 경우에는 아래와 같이 두 번째 함수가 실행됩니다. 두 번째 함수가 실행됩니다. 성공만 처리하고 싶으면 인수를 하나만 전달하면 됩니다.
2. catch
에러가 발생한 경우만 다루고 싶다면, .catch 를 쓰면 됩니다.
let promise = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error("에러 발생!")), 1000);
});
// .catch(f)는 promise.then(null, f)과 동일하게 작동합니다
promise.catch(alert); // 1초 뒤 "Error: 에러 발생!" 출력
.catch(f)는 문법이 간결하다는 점만 빼고 .then(null,f)과 완벽하게 같습니다.
💡 처리 되지 못한 Error는?
에러를 처리하지 못하면 무슨 일이 생길까요? 체인 끝에 .catch를 추가하지 못하는 경우같은 경우입니다. 이런 경우엔 js엔진은 프라미스 거부를 추적하다가 실패하면 전역 에러를 발생시킵니다. 브라우저에선 이런 에러를 unhandledrejection 이벤트로 처리할 수 있습니다.
unhandledrejection 이벤트는 HTML 명세서에 정의된 표준 이벤트입니다. 브라우저 환경에선 에러가 발생했는데 .catch가 없으면 unhandledrejection 핸들러가 트리거 됩니다.
3. finally
try {...} catch {...}에 finally 절이 있는 것처럼, 프라미스에도 finally가 있습니다.
finally 핸들러엔 인수가 없습니다. finally에선 프라미스가 이행되었는지, 거부되었는지 알 수 없습니다. finally에선 ‘보편적’ 동작을 수행하기 때문에 성공·실패 여부를 몰라도 됩니다.
또한, finally 핸들러는 자동으로 다음 핸들러에 결과와 에러를 전달합니다.
new Promise((resolve, reject) => {
setTimeout(() => resolve("결과"), 2000)
})
.finally(() => alert("프라미스가 준비되었습니다."))
.then(result => alert(result)); // <-- .then에서 result를 다룰 수 있음
실습 예제
프로미스로 지연 만들기
function delay(ms) {
return new Promise((resolve,reject) => {
setTimeout(resolve,ms)
})
}
delay(3000).then(() => alert('3초후 실행'));