[weekly] [nb] 웹 개발 시작하기(4)
프로미스(promise)의 3가지 상태에 대해 설명해 주세요.
약속(promise)
javascript 에서 비동기 프로그래밍을 보다 편하고 직관적이게 하기 위해 만든 기능이다.
es6(2015) 공식 표준화
javascript 로 비동기 작업을 많이 하게 되면서, 공통된 표준 문법으로 비동기 작업을 할 수 있도록 규정했다.
이때 아래의 조건을 충족할 수 있도록 여러 프로그래밍 언어에서 개념을 차용해왔다.
- 비동기 작업을 값 처럼 사용
- 중첩이 아니라 체이닝(chaining) 으로 흐름 작성
- 에러 처리 통합
e 언어
공식적으로 promise 라는 용어와 개념이 명확하게 사용된 언어는 e 언어(1990년대 중반)다.
상품 택배 배송
promise 의 과정은 대단히 단순하다.
우리가 쿠팡에서 물건을 샀을 때 택배로 배송오는 걸 생각하면 편하다.
deleivery-product.mjs 코드
// deleivery-product.mjs
export function deliverProduct(isAddressCorrect = true) {
return new Promise((resolve, reject) => {
console.log("배송 중 : 택배 집하소 도착(pending)")
setTimeout(() => {
if (isAddressCorrect) {
resolve("배송 성공 : 택배 도착(fulfilled)")
} else {
reject("배송 실패 : 주소 오류(rejected)")
}
}, 1000)
})
}
index.js 코드
// index.js
import { deliverProduct } from './delivery-product.mjs'
console.log("택배 배송 시작")
async function trackProduct() {
try {
const result = await deliverProduct(true)
console.log("성공:", result)
} catch (error) {
console.error("실패:", error)
}
}
trackProduct()
배송 시작
console.log("택배 배송 시작")
쿠팡이 주문을 받고 택배 배송을 시작했다.
대기(pending)
아직 배송 중이기 때문에 해당 배송이 성공이었는지, 실패였는지 알 수 없다.
return new Promise((resolve, reject) => {
console.log("배송 중 : 택배 집하소 도착(pending)")
// ...
})
쿠팡에서 물건을 택배 집하소에 가져다 두었다.
이제 쿠팡맨들이 각자 담당한 지점에 따라서 이 물건을 가지고 배송을 이어갈 것이다.
성공(fulfilled)
주소가 정확하게 입력이 되었다면 배송은 문제없이 진행될 것이다.
setTimeout(() => {
if (isAddressCorrect) {
resolve("배송 성공 : 택배 도착(fulfilled)")
} // ...
}, 1000)
promise 에서는 이 성공한 결과를 resolve() 에 담아서 보낼 수 있다.
아까 상기한 1. 비동기 작업을 값 처럼 사용 의 경우가 바로 이것이다.
실패(rejected)
하지만 배송 주소가 잘못 입력되었을 경우 물건은 다른 주소에 배송된다.
쿠팡 입장에서는 적힌 주소대로 보낸 것이긴 하지만, 어쨋든 우리 입장에서는 택배가 배송오지 못했다.
setTimeout(() => {
//...
else {
reject("배송 실패 : 주소 오류(rejected)")
}
}, 1000)
이때 javascript 는 reject() 에 담아서 오류를 보낸다.
async, await
직관적인 단어 비동기(async) 기다림(await) 을 사용해서 비동기 프로그래밍이 가능하다.
async function example() {
try{
const result = await something()
console.log(result)
} catch(error){}
}
표준으로 정립된 문법에서는 await 는 반드시 async 가 사용된 함수 안에서 사용되어야 한다.
간혹 그냥 .js 파일 안에서 바로 쓰는 경우가 있는데, 그 경우엔 동작은 한다.
하위호환성 과 여러가지 이유로 가능은 하게 해둔 것인데, 의도치 않은 버그가 생길 수 있다. 그리고 그것에 관해서는 프로그래머 본인의 책임일 뿐이다.
그래서 무조건 await 는 async 로 감싸진 함수에서 꼭 쓸 것.
try, catch
async 함수를 만들 때는 try {} catch(){} 를 항상 셋트로 사용하자.
async function example() {
try{
console.log('good')
} catch(error){
console.error('bad : ${error}')
}
}
express 를 사용하다보면 수없이 api 요청과 응답을 받는데 이때 마다 에러를 확인하기가 편하다.
async 를 사용할 때는 그냥 항상 기본값으로 쓴다는 생각으로 쓰자.
마무리
promise 를 객체로 만들어서 쓰는 것은 처음 해봤다.
기존에 만들어져 있는 기능들을 가져와서 쓸 때 async, await 를 많이 썼는데, 이번에 Promise 객체로 setTimeOut 을 감싸서 사용하니까 어떻게 써먹는지 이해가 되었다.
setTimeOut 은 Promise 객체가 아니라서 Promise 로 감싸면 await 로 딜레이를 줄 수 있다.
그런데 실무에서 이 setTimeOut 을 쓸지는 잘 모르겠다.
굳이 쓴다면 의도적으로 응답 시간을 넘겨서 timeout 을 테스트하는 정도..?