우선 Promise 로 관리할 비동기 작업을 만들 때에는, Promise 에서 요구하는 방법대로 만들어야 합니다. 여러가지 방법이 있지만 제일 정석적인 방법은 new Promise(...) 하는 것입니다. 아래 예제 코드를 봐주세요.
const promise1 = new Promise((resolve, reject) => {
// 비동기 작업
});
Plain Text
복사
복사하기
문법적으로 보충 설명해보겠습니다.
1.
변수의 이름은 promise1 이며, const 로 선언했기 때문에 재할당이 되지 않습니다. 하나의 변수로 끝까지 해당 Promise 를 관리하는 것이 가독성도 좋고 유지보수도 하기 좋습니다.
2.
new Promise(...) 로 Promise 객체를 새롭게 만들었습니다. 생성자는 함수이므로 괄호() 를 써서 함수를 호출하는 것과 동일한 모습입니다.
3.
이 특별한 함수를 공식 문서에서는 executor 라는 이름으로 부릅니다. 이 함수에 대해 더 자세히 설명하면 다음과 같습니다.
1.
executor는 첫번째 인수로 resolve 이며, 두번째 인수로 reject 를 받습니다. (이름은 우리가 정의하는 거라서 아무렇게나 해도 사실 상관은 없지만, 국룰을 따르도록 합시다.)
2.
resolve 는 executor 내에서 호출할 수 있는 또 다른 함수입니다. resolve 를 호출하게 된다면 “이 비동기 작업이 성공했어!” 라는 뜻입니다.
3.
reject 또한 executor 내에서 호출할 수 있는 또 다른 함수입니다. reject 를 호출하게 된다면 “이 비동기 작업이 실패했어…” 라는 뜻입니다.
•
executor 내부에서 에러가 throw 된다면 해당 에러로 reject 가 수행됩니다.
•
executor 의 리턴 값은 무시됩니다.
•
첫 번째 reject 혹은 resolve 만 유효합니다. (두 번째부터는 무시됩니다. 이미 해당 함수가 호출되었다면 throw 또한 무시됩니다.)
a를 쓰는 콘솔로그라면? 1이 먼저 콘솔 출력된다.
a는 사용할 때 기다려라(await)
await해놓았기 때문에 return responseData에서 참조할 때 await인 걸 알기 때문에 비동기 작업을 기다렸다가 참조해서 사용한다. (await 없이 response.json()하면 프로미스.json()이므로 프로미스가 그대로 반환됨)
a에 할당된 에러여도 a를 사용하지않는다면 catch문으로 에러가 잡히지 않는다.
내부는 일단 프로미스 객체이므로 이걸 배열화하는 과정이 await Promise.all([]).then(promises ⇒ promises.map(...json()))
이렇게 배열화되면 다시 await Promise.all에 담아둘 수 있다.
const getMoviesDetailsById = async movieId => {
try {
const [responseData, responseCreditsData, responseCertificationData] = await Promise.all(
await Promise.all([
fetch(`${apiBaseUrl}movie/${movieId}?api_key=${apiKey}`),
fetch(`${apiBaseUrl}movie/${movieId}/credits?api_key=${apiKey}`),
fetch(`${apiBaseUrl}movie/${movieId}/release_dates?api_key=${apiKey}`),
]).then(promises => promises.map(promise => promise.json()))
);
JavaScript
복사
(내부 코드의 출력 결과)
한번 더 await해야 값을 가져올 수 있는 것..
왜? 각각이 딱 Promise 객체여야 한다. 아래의 케이스도 map내부에서 async로 만들어 줬기 때문에 하나하나가 Promise 객체가 된다
await Promise.all(movies.map(async movie => ({
...movie, ...(await getMoviesMainDetails(movie.id))
})
));
JavaScript
복사
Promise.all([
fetch(`${apiBaseUrl}movie/${movieId}?api_key=${apiKey}`),
fetch(`${apiBaseUrl}movie/${movieId}/credits?api_key=${apiKey}`),
fetch(`${apiBaseUrl}movie/${movieId}/release_dates?api_key=${apiKey}`),
])
JavaScript
복사
이게 한 뭉치로 들어온다. 그러니까 then으로 promises를 받아서 그걸 map을 돌리는 위의 방식 OR await로 변수에 받은다음 그 변수를 받아서 다시 Promise.all에 넣는 방식
만약 Promise { <Pending> }을 바로 map 돌리려고 하면 객체이므로 안된다. await를 붙였더라도 Promise { <Pending> }.map()이 먼저 다 된다음에 await가 역할을 하기 때문이다. await Promise { <Pending> }을 먼저 끝낼 수 있다면 여기서 나온 배열을 map() 돌릴 수 있지만 변수를 하나 더 선언해야한다.
await Promise.all([
fetch(`${apiBaseUrl}movie/${movieId}?api_key=${apiKey}`),
fetch(`${apiBaseUrl}movie/${movieId}/credits?api_key=${apiKey}`),
fetch(`${apiBaseUrl}movie/${movieId}/release_dates?api_key=${apiKey}`),
]).then(promises => promises.map(promise => promise.json()))
JavaScript
복사
(Promise.all에 then으로 resolve된 값을 사용하는 예제)
movies.map is not function
초기값을 문자열로 줘서 fetch되기 전에는 false가 나온다.
빌드 시간이 오래 걸리므로 webpack-devserver
node-fetch는 테스트용, axios를 사용하는 것이 좋다. (import는 아직 베타)
업무 분배
•
검색
•
마이페이지
const parseToJSON = res => {
if (!res.ok) {
// throw new Error(res.status);
}
return res.json();
};
export default {
get(url) {
return fetch(url).then(parseToJSON); // then이 한줄 덜 쓸 수 있다.
},
post(url, payload) {
return fetch(url, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify(payload),
}).then(parseToJSON);
},
patch(url, payload) {
return fetch(url, {
method: 'PATCH',
headers: { 'content-type': 'application/json' },
body: JSON.stringify(payload),
}).then(parseToJSON);
},
delete(url) {
return fetch(url, { method: 'DELETE' }).then(parseToJSON);
},
};
JavaScript
복사
env
⇒ 추측 : env파일을 gitignore에 올렸어도 git cashed되어있다면 그걸 지운다음 적용해야 gitignore처리가 된다.
검색결과 배열에 국가가 없음 api 확인
searchMoviesByKeyword 함수에 getMoviesWithCountry() 호출하는 로직 추가