JavaScript는 싱글 스레드 기반 언어로, 한 번에 하나의 작업만 처리한다.
하지만 웹 환경에서는 서버 통신, 파일 읽기, 타이머처럼 시간이 오래 걸리는 작업들이 많은데,
이러한 작업들이 동기적으로 처리되면, UI나 다른 작업이 멈추거나 느려질 수 있기 때문에
비동기 처리(Asynchronous) 방식이 필요하고, 이를 효율적으로 다루기 위해 Promise 객체를 사용한다.
Promise는 “미래에 완료될 작업에 대한 약속”을 표현하는 비동기 처리 객체로
비동기 작업의 성공/실패 결과를 나중에 처리할 수 있도록 상태를 갖고 흐름을 제어합니다.
const myPromise = new Promise((resolve, reject) => {
// 비동기 작업 수행
let success = true; // 예시 조건
if (success) {
resolve("작업이 성공했습니다."); // 작업 성공 시 호출
} else {
reject("작업이 실패했습니다."); // 작업 실패 시 호출
}
});
Promise의 상태| 상태 | 설명 |
|---|---|
pending | 대기 상태 (아직 작업이 끝나지 않은 초기 상태) |
fulfilled | 성공 완료 상태 (resolve() 호출됨) |
rejected | 실패 상태 (reject() 호출됨) |
Pending 상태에서 시작하며, 이후 Fulfilled 또는 Rejected 상태로 변경된다.
.then(), .catch(), .finally() 사용Promise 객체는 then()과 catch() 메서드를 사용하여 이행되거나 거부된 이후의 처리를 정의할 수 있다.
myPromise
.then((result) => {
console.log(result); // "작업이 성공했습니다."
})
.catch((error) => {
console.error(error); // "작업이 실패했습니다."
});
.finally(() => {
console.log("작업 종료 (성공/실패 상관없이)");
});
위 예시 코드는 myPromise가 성공적으로 이행되면 then 블록이 실행되며, 거부되면 catch 블록이 실행된다. (finally는 항상 실행)
Promise가 이행되었을 때, 또는 거부되었을 때 각각 호출될 콜백 함수를 지정한다.
이 메서드는 또 다른 Promise를 반환하므로, then 체인을 사용하여 여러 비동기 작업을 순차적으로 처리할 수 있다.
myPromise.then(result => {
console.log("성공 결과:", result);
});
Promise가 거부되었을 때 호출될 콜백 함수를 지정한다.
주로 에러 처리를 위해 사용한다.
myPromise.catch(error => {
console.error("에러 발생:", error);
});
Promise의 성공/실패 관계없이 항상 실행한다.
myPromise.finally(() => {
console.log("작업 종료 (성공/실패 상관없이)");
});
fetch와 함께 쓰는 Promisefetch("https://api.example.com/data")
.then(response => {
if (!response.ok) throw new Error("응답 실패");
return response.json();
})
.then(data => console.log("데이터:", data))
.catch(error => console.error("에러:", error))
.finally(() => console.log("요청 종료"));
Promise 체이닝Promise는 then() 메서드로 체이닝이 가능하여, 순차적으로 비동기 작업을 처리할 수 있다.
체이닝을 통해 여러 비동기 작업을 순차적으로 실행하고, 중간 단계에서 발생한 에러를 처리할 수 있다.
new Promise((resolve, reject) => {
resolve(1);
})
.then((result) => {
console.log(result); // 1
return result * 2;
})
.then((result) => {
console.log(result); // 2
return result * 3;
})
.then((result) => {
console.log(result); // 6
})
.catch((error) => {
console.error(error);
});
위 예제에서는 Promise 체이닝을 통해 각각의 then 블록에서 결과를 처리하고, 다음 단계로 전달하고 있다.
Promise.all()Promise.all() 메서드는 여러 개의 Promise를 병렬로 처리할 때 유용한데 주어진 모든 Promise가 이행될 때까지 기다린 후, 그 결과를 배열로 반환한다.
하나라도 거부되면 Promise.all()은 즉시 거부된다.
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then((values) => {
console.log(values); // [3, 42, "foo"]
});
Promise.all()은 병렬로 여러 비동기 작업을 수행하고, 모든 작업이 완료된 후에 결과를 한 번에 처리하는 데 유용하다.
Promise.race()Promise.race() 메서드는 여러 개의 Promise 중 가장 먼저 이행되거나 거부된 Promise의 결과를 반환한다.
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); // "two"
});
위 예제를 보면 promise2가 더 빨리 이행되므로 Promise.race()는 "two"를 출력한다.
Promise.finally()Promise.finally() 메서드는 Promise가 이행되든 거부되든, 마지막에 실행되어야 할 코드를 작성할 때 사용한다.
(finally 블록은 결과에 관계없이 항상 실행됨)
myPromise
.then((result) => {
console.log(result);
})
.catch((error) => {
console.error(error);
})
.finally(() => {
console.log("Promise가 완료되었습니다."); // 항상 실행
});
이 메서드는 리소스 해제, 로딩 상태 해제 등 반드시 수행해야 할 작업을 정의하는 데 유용합니다.
Promise 체이닝 에러 처리 주의점Promise 내부에서 발생한 에러는 반드시 .catch() 또는 try/catch로 처리해야 한다.
Promise 체이닝에서 에러가 발생하면, 발생 지점에서 가장 가까운 catch() 블록으로 에러가 전달되는데 catch() 블록을 여러 개 사용할 수도 있지만, 마지막에 하나만 두는 것이 일반적인 방법이다.
new Promise((resolve, reject) => {
throw new Error("에러 발생!");
})
.then((result) => {
console.log(result);
})
.catch((error) => {
console.error("에러를 잡았습니다:", error.message); // "에러를 잡았습니다: 에러 발생!"
})
.finally(() => {
console.log("작업 완료");
});
위 예시에서는 Promise 내에서 에러가 발생했으나, catch() 블록에서 이를 처리하고, finally() 블록에서 추가 작업을 수행한다.
| 개념 | 설명 |
|---|---|
| Promise | 미래에 결과가 나오는 비동기 작업을 다루는 객체 |
| 상태 | pending → fulfilled 또는 rejected |
| then | 성공 시 실행되는 콜백 |
| catch | 실패 시 실행되는 콜백 |
| finally | 무조건 실행되는 정리용 콜백 |
| all | 모든 Promise가 성공해야 완료 |
| race | 가장 먼저 완료된 Promise 하나만 처리 |
| fetch | 서버 요청 시 자주 쓰이며 Promise 기반으로 응답 처리 |