| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |
- html
- javascript
- js
- dbeaver
- 정보처리기사
- SQL Server
- my sql
- Java
- mybatis
- svn
- programmers
- jquery
- mysql
- Linux
- STS
- SQL
- node.js
- reCAPTCHA
- urlshortner
- Mac
- spring
- shorturl
- Tomcat
- Eclipse
- IntelliJ
- Oracle
- maria db
- windows
- TIP
- devlog
- Today
- Total
고양의 성장일기
[Javascript] 자바스크립트 비동기 3부작 <약속의 Promise> 본문
자바스크립트 비동기 3부작 <약속의 Promise>
자바스크립트는 기본적으로 단일 스레드를 가지고 동작하기 때문에 시간이 오래 걸리는 작업을 동기적으로 처리하면 종종 화면이 멈추는 문제가 발생합니다.
이 문제를 해결하기 위해 자바스크립트는 비동기 처리 방식을 제공하는데,
비동기를 처리하는 여러 가지 방법 중 하나가 이번 글에서 알아볼 Promise입니다.
Promise가 뭐죵
지금 당장은 결과를 알 수 없지만 나중에 언젠가 성공 또는 실패의 결과를 반환할 작업을 표현하는 객체입니다.
Promise는 작업의 상태(State)와 결과(result)를 관리하며 항상 아래 3가지 상태 중 하나를 가지게 됩니다.
- Pending : 아직 처리중이유
- fulfilled : 성공했슈
- rejected : 실패했슈
약속 잡기 Promise 생성하기
Promise 객체를 생성하고 변수에 할당하는 방식으로 새로운 Promise를 생성할 수 있습니다.
const promise = new Promise((resolve, reject) => {
// 비동기 작업 수행
if (성공조건) {
resolve(결과값);
} else {
reject(에러);
}
});
Promise가 작업을 완료하면 성공, 실패 결과에 따라 매개변수로 받은 콜백을 실행합니다.
Promise 결과 처리하기
여기까지 봤을 땐 예전에 사용하던 콜백 방식과 큰 차이가 없는 것 같습니다.
하지만 Promise의 진가는 여러 개의 콜백을 처리하거나 예외처리를 해야 할 때 빛이 납니다.
예외처리하기
Promise의 결과는 메서드 체이닝 방식으로 처리됩니다.
promise
.then(result => {
console.log('성공:', result);
})
.catch(error => {
console.error('실패:', error);
})
.finally(() => {
console.log('항상 실행');
});
- then()
→ resolve 되었을 때 실행 - catch()
→ reject 되었을 때 실행 - finally()
→ 성공/실패와 관계없이 항상 실행
여러 작업 체이닝 하기
또 then()은 새로운 Promise를 반환하기 때문에, 성공 여부에 따른 연속 처리가 가능합니다.
비동기 작업을 순차적으로 처리할 수 있게 해 주고 이른바 callback hell을 방지할 수 있는 것이죠.
fetch('/api/data')
.then(res => res.json())
.then(data => {
return data.value;
})
.then(value => {
console.log(value);
})
.catch(error => {
console.error(error);
});
fetch API 또한 Promise 객체를 반환하기 때문에 메서드 체이닝을 통해 여러 가지 후속 작업과 예외 처리가 가능합니다.
Promise 좀 더 깊게 알아보기
자바스크립트의 Promise는 단순히 예외처리를 편하게 하기 위한 개념이 아닙니다.
Promise 객체가 제공하는 메서드들을 응용하면 여러 비동기 객체를 조합, 제어, 생성, 정규화하여 여러 가지 상황에 대처할 수 있습니다.
1. 여러 Promise 조합하기
1-1. Promise.all()
매개변수로 받은 모든 Promise가 성공해야만 성공입니다.
Promise.all([p1, p2, p3])
.then(results => {
console.log(results); // [result1, result2, result3]
})
.catch(error => {
console.error(error);
});
하나라도 reject 되면 즉시 reject를 반환하며
결과는 입력 순서 그대로 배열로 반환됩니다.
병열 처리 후 전체적인 결과가 필요할 때 사용됩니다.
1-2. Promise.allSettled()
성공, 실패 여부와 관계없이 모두 완료되면 각각의 Promise에 대한 결과를 반환합니다.
Promise.allSettled([p1, p2])
.then(results => {
console.log(results);
});
결과는 아래와 같이 구분되어 반환됩니다.
[
{ status: 'fulfilled', value: ... },
{ status: 'rejected', reason: ... }
]
요청이 실패해도 전체 결과를 받을 수 있으며 catch가 아닌 then에서 처리됩니다.
일부 실패가 허용되는 작업에서 사용하거나 다량의 요청을 보낼 때 서버의 과부하를 방지할 수 있습니다.
만약 Promise.all()을 사용해 여러 개의 fetch요청을 보냈고 하나라도 실패할 경우 모든 요청을 다시 보내야 한다고 가정하면,
서버는 "아니 실패한 거만 따로 떼서 보내든가 왜 다 다시보내지"라고 생각할 수도 있겠죠.
반대로 클라이언트에서도 "아니 실패한거만 다시 처리를 하든가 왜 전부 다 결재를 올리래"라고 생각할 수도 있습니다.
그럴 때 rejected의 Promise만 추출해서 재요청하면 서버도 과부하를 덜고 클라이언트에서도 좀 더 안정적으로 요청을 관리할 수 있게 됩니다.
1-3. Promise.race()
가장 먼저 응답받은 Promise의 결과를 사용합니다.
Promise.race([p1, p2])
.then(result => {
console.log(result);
})
.catch(error => {
console.error(error);
});
성공/실패 여부는 중요하지 않으며 가장 빠른 Promise 하나만 반영됩니다.
타임아웃 처리를 하거나 여러 개의 요청 중 신속한 응답을 필요로 할 때 사용됩니다.

1-4. Promise.any()
가장 먼저 성공한 Promise 하나만 반환합니다.
reca()가 가장 먼저 성공, 실패 여부와 관계없이 "하지만 빨랐죠?" 드립을 날리는 메서드라면 any() 메서드는 성공을 보장합니다.
Promise.any([p1, p2])
.then(result => {
console.log(result);
})
.catch(error => {
console.error(error); // 모든 Promise가 실패했을 때
});
여러 대체 수단 중 하나만 성공하면 되는 경우 사용합니다.
2. Promise를 생성·정규화하는 메서드
2-1. Promise.resolve()
값을 즉시 성공한 Promise로 반환합니다.
Promise.resolve(10)
.then(value => {
console.log(value); // 10
});
Promise가 아닌 값도 Promise로 통일할 수 있기 때문에 함수가 Promise를 반환하도록 인터페이스를 정리하거나
동기/비동기로 혼합된 코드를 정리할 때 유용합니다.
2-2. Promise.reject()
resolve() 메서드와 달리 즉시 실패한 Promise를 생성합니다.
Promise.reject(new Error('실패'))
.catch(error => {
console.error(error);
});
테스트나 에러 흐름 강제 분기 시 사용하면 좋습니다.
3. Promise 결과를 처리하는 인스턴스 메서드
3-1. then()
Promise 성공 시 실행됩니다.
promise.then(result => {
return result + 1;
});
새로운 Promise를 반환하기 때문에 then() 체이닝이 가능합니다.
이 경우 return 된 값은 다음번 then()으로 전달됩니다.
3-2. catch()
Promise가 실패했을 경우 실행됩니다.
promise.catch(error => {
console.error("예외 발생: ", error);
});
catch() 블록은 체이닝 중 한 번만 포함되면 충분하며, 어느 단계의 에러든 처리가 가능합니다.
3-3. finally()
성공/실패와 무관하게 언제나 실행되는 블록입니다.
promise.finally(() => {
console.log('정리 작업');
});
결과값을 변경하지 않기 때문에 로딩을 종료하거나 리소스를 해제하는 등의 작업에 적합합니다.
마치며
Promise는 단순한 하나의 비동기 객체가 아니라 비동기의 전체적인 흐름을 제어하기 위한 하나의 도구로 보는 것이 좋습니다.
위 정리된 메서드들을 정확히 이해하면
- 복잡한 비동기 API 흐름 정리
- 실패와 성공 전략을 명확히 구분하여 설계
- 다음에 나올 async/await 구조에서도 내부 동작을 이해할 수 있는
능력치를 가지게 됩니다.
긴 글 읽어주셔서 감사합니다. 다음 번 글로는 async / await로 찾아오겠습니다.
'🖥️ Front-End > Javascript' 카테고리의 다른 글
| [Javascript] 자바스크립트 비동기 3부작 <Callback> (0) | 2025.12.17 |
|---|---|
| [Javascript] 자바스크립트 비동기 3부작 <async / await> (1) | 2025.12.15 |
| [Javascript] Fisher-Yates 알고리즘으로 랜덤 값 가져오기 (3) | 2025.12.15 |
| [Javascript] "==" 그리고 "===" (0) | 2025.10.10 |
| [Javascript] 객체 접근법 파헤쳐보기, 점 표기법 vs 대괄호 표기법 (8) | 2025.08.07 |