TIL

2024.01.12 TIL # Promise.then # async / await

inz1234 2024. 1. 15. 01:39

오늘 배운 것

1. browser 1개 당 1개의 html만 가질 수 있다.

- 코딩하면서 그냥 문득 궁금했던 것이 index.html이

  <script type="module" src="./src/main.js"></script>

main.js를 가져오고, main.js가 다시 movie.js를 import하고 detail.js가 movie.js에 있는 것들을 import 하면 detail.html이 detail.js을 type=module 한다면 detail.html과 index.html이 연결된 것이 아닐까? 
했는데 브라우저 1개 당 1개의 html 파일을 가질 수 있다고 한다ㅋㅋ

 

2. 전역객체에서 선언된 변수는 지역변수로 쓰일 수 있지만, 함수 등 지역에서 선언된 변수는 전역에서 선언될 수 없다.

 

- call stack에 전역이 제일 아래에 있기 때문에 아래에서 선언된 변수는 위에 쌓이는 stack에서 사용할 수 있지만, 위 stack에서 선언된 변수는 밑에서 사용할 수 없다는 얘기

 

- 그렇기 때문에 함수 하나하나를 분리해서  차라리 더 큰 함수 주머니를 만들어서 그 안에 함수들을 넣어버리는 게 깔끔하다.

-> 나중에 변수를 차용할 때 용이하기 때문이다.

아주 기본적인 이것을 제대로 이해를 안하고 넘어갔어서 은근 코딩할 때 애를 맥였다.

 

3.  await는 뒤에 오는 promise 함수의 "fullfilled 된 상태까지만" 기다려주고 .then문까지는 기다려주지 않는다.

- promise.then 과 async / await는 둘 다 Promise 함수의 상태가 "fulfilled"까지 될 때까지 기다린 뒤에 .then문을 실행 or 그 뒤 나머지 코드를 실행하라는 의미이다.

   await fetchMovies();

 

  const movies = getMovies();

 

  console.log(movies);

- 이 코드는 상세페이지의 detail.js 파일이다.

 

- fetchMovies() 함수가 어떤 애냐면

  export async function fetchMovies() {
   Promise.all([
  ])

 

    .then((responses) => Promise.all(responses.map((response) => response.json())))
    .then(([moviesResponse, genresResponse]) => {
      movies = moviesResponse.results; // 영화 데이터를 배열에 저장
      genres = genresResponse.genres; // 장르 데이터를 배열에 저장
    })
    .catch((err) => console.error(err));
}

- 메인페이지 movie.js 파일의, 외부에서 데이터를 불러오는 함수다. 

- 내가 의도했던 것은 detail.js파일에서 fetchMovies() 앞에 await를 붙임으로써 fetchMovies()가 다 실행된

  다음에, 즉 데이터가 다 불려와진 다음에 밑에 console.log(movies)가 실행될 줄 알았는데 그렇지 않았고

  fetchMovies가 다 완료되지도 않았는데 console창에 movies가 찍혔고 +  데이터도 불려오지 않았다.

->  이것은 detail.js의 await 가 적용되는 범위가 promise.all 안의 fetch(1) / fetch(2) 까지이고, .then문까지는 뻗치지 못해서, 데이터를 온전히 불러오지 못 했다 말이다.

 

왜 그럴까? 

 

- await에 대해서 열심히 찾아본 결과,

  await는 "promise의 fulfilled된 상태" 까지만 기다려주고 그 이후의 .then 체인까지는 기다려주지 않는다는    것이다.

 그렇기에 내 코드에서도 데이터를 다 불러오기를 원했어서 await fetchMovies( ) 라고 했지만,  

 이 await는 fetchMovies 안의 promise.all 안의 promise들의 fullfilled 된 상태까지만 기다리고 밑에     

  console.log(movies)가 바로 실행된 것이었다.

 

- 그럼 어떻게 해야 내 의도대로 코드를 쓸 수 있을까?

  애초에 fetchMovies라는 함수를 데이터를 완전히 불러오는 것 까지를 한 덩어리로 묶어버리면 되지 않을까?

  OK fetchMovies 함수에도 async / await 적용시켜 버려야겠다.

 

그렇게 탄생한 나의 코드는

 

   export async function fetchMovies() {
  await Promise.all([
  ])

 

    .then((responses) => Promise.all(responses.map((response) => response.json())))
    .then(([moviesResponse, genresResponse]) => {
      movies = moviesResponse.results; // 영화 데이터를 배열에 저장
      genres = genresResponse.genres; // 장르 데이터를 배열에 저장
    })
    .catch((err) => console.error(err));
}

이거다.

promise.all 앞에 await를 붙여줌으로써 .then까지 다 실행된  거 자체를 fetchMovies 로 만들어 버렸다.

 

+) promise.all 함수를 공부하다가 들었던 궁금증이 있다.

1) promise.all 에서 .then( ) 과 await는 promise가 fulfilled 상태가 될때까지 기다린다고 했는데, 만약 promise.all 안에 한 promise는 fulfilled고, 다른 하나는 rejected면 어떻게 될까?

 

=> Promise.all() 내의 모든 프로미스가 fulfilled 상태여야만 await 또는 .then 이후의 코드가 실행된다.

 

예를 들어, 

try {
  await Promise.all([
    fetch(url1),
    Promise.reject(new Error("Some error")),
    fetch(url3)
  ]);
} catch (error) {
  console.error(error); // "Some error"
}

 

이 코드에서 두 번째 promise의 상태가 rejected이기 때문에 뒤에 있을 await 함수가 실행되지 않고, catch 블록으로 이동한다.