Promise
- 비동기 작업을 제어하기 위해 나온 개념으로, callback hell에서 어느정도 벗어날 수 있게 해준다
- Promise로 정의된 작업끼리는 연결할 수 있으며, 이를 통해 코드의 depth가 크게 증가하지 않는 효과가 있다
const promise = new Promise((resolve, reject) => {
// promise 내부에서 비동기 상황이 종료될 때, resolve 함수 호출
// promise 내부에서 오류 상황일 때, reject 함수 호출
})
- Promise에서는 then을 이용해 비동기 작업 이후 실행할 작업을 지정한다
function asyncPromiseWork() {
// ....
return new Promise((resolve, reject) => {
// ....
return resolve('complete')
})
}
// then의 result에는 resolve를 호출하면 넘긴 complete가 들어있음
asyncPromiseWork().then(result => console.log(result))
- Promise의 then 내에서 promise를 return할 경우 이어진다
- Promise chain 중 작업이 실패했을 경우, .catch로 잡을 수 있다. catch를 중간에 넣고 이후 작업을 연결해도 동작한다. catch를 안넣을 경우 promise chain 중 에러가 발생했을 때 chain이 멈추니 가급적 넣는게 좋다
- 성공과 실패 여부와 상관없이 호출해야 하는 코드가 있다면 finally에서 처리한다
promiseWork()
.then(result => {
return promiseNextWork(result)
}).then(result => {
return promiseThirdWork(result)
}).then(result => {
return promiseFinalWork(result)
}).catch(e => {
alert('에러 발생')
}).finally(() => {
alert("어쨋든 작업은 끝남")
})
- 기존의 callback 함수를 promise 형태로 만들 수 있다. resolve를 작업이 끝나는 순간에 호출하면 된다
const delay = (delayTime) => new Promise((resolve) => {
setTimeout(resolve, delayTime)
})
delay(5000)
.then(() => {
doSomething()
return delay(3000)
}).then(() => {
console.log('complete');
})
Promise 내장 함수
- Promise.all(iterable) : 여러 promise를 동시에 처리할 때 유용하다
- Promise.race(iterable) : 여러 promise 중 하나라도 resolve 혹은 reject되면 종료된다
- Promise.any(iterable) : 여러 promise 중 하나라도 resolve가 되면 종료된다 (Promise.race()와 비슷)
- Promise.allSettled(iterable) : 여러 promise들이 성공했거나 실패했거나 상관없이 모두 이행된 경우를 처리할 수 있다
- Promise.resolve : 주어진 값으로 이행하는 Promise.then 객체를 만든다. 주어진 값이 Promise인 경우 해당 Promise가 반환된다
- Promise.reject : 주어진 값으로 reject 처리된 Promise.then 객체를 만든다. 주어진 값이 Promise인 경우 해당 Promise가 반환된다
async, await
- Promise가 callback depth를 1단계로 줄여주긴 하지만, 여전히 불편하다
- async, await를 이용하면 실행은 비동기로 실행되지만 Promise를 동기 코드처럼 보이게 짤 수 있다
const work = () => {
console.log('work run');
delay(1000)
.then(() => {
console.log('work 1 complete.');
return delay(1000);
}).then(() => {
console.log('work 2 complete.');
return delay(1000);
}).then(() => {
console.log('work 3 complete.');
return delay(1000);
}).then(() => {
console.log('work all completed');
})
console.log('work running..');
}
work()
다음 코드를 async, await로 아래와 같이 구현할 수 있다
const work = async() => {
console.log('work run');
await delay(1000);
console.log('work 1 complete.');
await delay(1000);
console.log('work 2 complete.');
await delay(1000);
console.log('work 3 complete.');
await delay(1000);
console.log('work all complted!');
}
work()
- async 키워드 함수가 붙은 함수는 실행 결과를 Promise로 감싼다
- 기본적으로 await는 async로 감싸진 함수 scope에서만 사용 가능했지만, top level await가 등장하여 top level에서도 가능하다
- promise에서 reject는 async, await에서 try~catch문을 사용하여 표현할 수 있다
try {
// 로딩중 보여주기 처리
} catch(e) {
// promise의 .catch와 비슷한 역할
} finally {
// promise .finally와 비슷한 역할
// 로딩중 숨겨주는 처리
}
fetch api
- 비동기 http 요청을 좀 더 쓰기 편하게 해주는 API
- XMLHTTPRequest을 대체
- Promise 기반으로 동작한다
fetch('url')
.then(res => {
return res.json()
})
.then(todos => {
// todos 조회 완료
console.log(todos);
})
fetch api 사용
- fetch의 기본 응답 결과는 Response 객체이다
- Response 객체를 얻은 뒤엔 응답을 json으로 바꾸거나 text로 바꾸는 등의 처리를 해줘야 한다
fetch('https://kdt-frontend.programmers.co.kr/todos')
.then(res => {
return res.text()
})
.then(data => {
console.log(data);
})
- response를 text로 바꾸면 json 형식이 되기 때문에 JSON.parse()를 이용하여 객체 형식으로 바꿀수 있다
- fetch('https://kdt-frontend.programmers.co.kr/todos') .then(res => { return res.text() }) .then(data => { console.log(JSON.parse(data)); })
- blob은 이미지 처리하는데 쓸 수 있다
- fetch는 HTTP error가 발생하더라도 reject되지 않는다. 네트워크 에러나 요청이 완료되지 못한 경우에만 reject된다
- 서버 요청중 에러가 생겼을 경우에도 then으로 떨어지므로, response의 status code나 ok를 체크해주는 것이 좋다
- fetch의 두번째 인자로 옵션을 줄 수 있다
fetch('https://kdt-frontend.programmers.co.kr/todos',{
method: 'POST',
headers,
body: JSON.stringify(todo)
})
존재하지 않는 API 호출해보기
fetch('https://kdt-frontend.programmers.co.kr/api-undefined')
.then(res => {
return res.json()
})
.then(data => {
console.log(data);
})
.catch(e => {
document.querySelector('body').innerHTML = e.message;
})
Unexpected token 'N', "Not Found" is not valid JSON 에러가 발생함
fetch('https://kdt-frontend.programmers.co.kr/api-undefined')
.then(res => {
if(res.ok) {
return res.json()
}
throw new Error(`Status: ${res.status}! 요청을 처리하지 못했어요.`)
})
.then(data => {
console.log(data);
})
.catch(e => {
document.querySelector('body').innerHTML = e.message;
})
- 다음과 같이 코드를 수정하면 res.ok인 경우에 res.json()이 return되고 밑에 catch문으로 가고 아닌 경우에 '요청을 처리하지 못했어요.'라는 메시지를 받는다
- res.status를 통해 response 상태를 알 수 있고 다음 코드에서는 에러 발생하기 때문에 에러 상태를 알 수 있다
- res.ok는 status가 200~299 사이인 경우 true가 된다
'👨💻 TIL' 카테고리의 다른 글
TIL - 2023.11.03 (0) | 2023.11.08 |
---|---|
TIL15 - 2023.10.12 (1) | 2023.10.15 |
TIL13 - 2023.10.09 (0) | 2023.10.10 |
TIL12 - 2023.10.06 (1) | 2023.10.07 |
TIL11 - 2023.10.05 (0) | 2023.10.06 |