## Promise란?
ES6에서 도입된 비동기 처리 객체로 기존 콜백 기반의 비동기 처리 방식의 단점(콜백 헬, 가독성 저하 등)을 해결하기 위해 만들어졌다.
비동기작업의 성공/실패를 표현하고, 작업 완료 이후의 처리를 명시적으로 제어할 수 있다.
`pending`, `fulfilled`, `rejected` 3가지 상태를 가지고, `.then()`, `.catch()`, `.finally()` 메서드 체이닝 방식으로 비동기 작업을 처리한다.
## Promise의 3가지 상태
* `pending` : **대기**. 초기 상태이고 아직 완료도, 실패도 아닌 상태
* `fulfilled` : **이행**. 연산이 성공적으로 완료된 상태 (resolve 호출됨)
* `rejected` : **거부**. 연산이 실패한 상태 (reject 호출됨)
상태는 한번 정해지면 바뀌지 않는다.
<!--todo: fulfilled와 resolve의 차이-->
## then, catch, finally
- `.then()` : `fulfilled` 상태일 때 호출되는 메서드
- `.catch()` : `rejected` 상태일 때 호출되는 메서드
- `.finally()` : 성공 여부에 관계없이 항상 실행되는 메서드
각 메서드는 Promise를 반환하기 때문에 체이닝이 가능하다. 체이닝을 통해서 순차적인 비동기 작업 처리가 가능하다.
```typescript
// Promise 체이닝
fetch('/api/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error))
.finally(() => console.log('end!'))
```
## 콜백 헬
연속적으로 수행되어야 하는 비동기 작업이 있을 때, 콜백 함수를 이용하면 콜백이 중첩되면서 가독성이 저하되고 에러 커처리가 복잡해지는 문제가 생긴다.
유저가 작성한 게시글과 게시글에 달린 댓글들을 가져오는 상황을 예로 들어보면,
```javascript
getUser(id, (user) => {
getPosts(user, (post) => {
getComments(posts[0], (comments) => {
console.log(comments);
})
})
})
```
중첩이 깊어지면서 가독성이 저하될 뿐 아니라 에러 처리를 위한 로직이 복잡해진다는 문제가 생긴다.
Promise의 메서드 체이닝을 이용하면 중첩 없이 직선적인 흐름으로 코드를 작성할 수 있어서 가독성이 높아진다. 에러 처리도 `.catch()` 메서드 하나로 가능하다는 장점이 생김.
```javascript
getUser(id)
.then(getPosts)
.then(posts => getComments(posts[0]))
.then(console.log)
.catch(console.error);
```
## 관련 링크
- [[async · await]]
- [[Promise와 async · await]]
- [[Promise.all]]
- [[Promise.allSettled]]
- [[Promise.race와 Promise.any]]