본문 바로가기
부트캠프 개발일지 2023-2024/Bootcamp 생활기록

[3주차] Promise( ), fetch( ), then( ), async( ), await( ), mouseover

by whereanna00 2023. 10. 19.

상황: TMDB 에서 API 를 통해 영화 데이터를 가져오면서 (TMDB측 에서 받은 fetch코드

fetch('https://api.themoviedb.org/3/tv/top_rated?language=en-US&page=1', options)
  .then(response => response.json())
  .then(response => console.log(response))
  .catch(err => console.error(err));

 

이 코드를 이해하기 전 알아야 할 점을 정리해본다.

 

1. fetch ()

- 배경

브라우저에서 fetch() 함수를 지원하기 이전에는, 원격 API호출을 위해 request나 axios, jQuery와 같은 라이브러리를 많이 썼었다. 라이브러리를 썼던 이유로는, 클라이언트 단에서 직접 HTTP 요청하고 응답을 받는 게 상당히 복잡했기 때문이다.

 

하지만 요즘에는 브라우저에 fetch() 함수가 내장되어 있기때문에, 굳이 이러한 라이브러리의 도움없이 fetch() 함수를 이용해도 충분하다. 오히려 이러한 현재 라이브러리를 사용하는 것이 자바스크립트 번들(bundle) 파일의 크기만 늘려서 낭비가 될 수 있다.

 

- 쓰는방법

fetch() 함수는 첫번째 인자로 URL, 두번째 인자로 옵션 객체를 받고, Promise 타입의 객체를 반환(=return)한다.

// 기본 골격
fetch(url, options) 
.
.
.
fetch(); // Promise();

Options는 객체이다.

Promise(); 란?
자바스크립트 비동기 처리에 사용되는 객체다. 여기서 자바스크립트의 비동기 처리란 ‘특정 코드의 실행이 완료될 때까지 기다리지 않고 다음 코드를 먼저 수행하는 자바스크립트의 특성’을 의미한다.

Promise의 상태(states)에는 3가지가 있는데,
(1) Pending(대기) : 비동기 처리 로직이 아직 완료되지 않은 상태
(2) Fulfilled(이행) : 비동기 처리가 완료되어 프로미스가 결과 값을 반환해준 상태
(3) Rejected(실패) : 비동기 처리가 실패하거나 오류가 발생한 상태

반환된 Promise 객체는, API 호출이 성공했을 경우에는 응답(response) 객체를 resolve하고, 실패했을 경우에는 예외(error) 객체를 reject합니다.

// 기본 골격
fetch(url, options) 
.
.
.
fetch(); // Promise();


Promise(function(resolve, reject) { 
	resolve();   // respond = { key : value, key1 : value1 ... }
    reject(); // error =  { key : value, key1 : value1 ...  }
    
};

 

이러한 과정을 아래와 같은 코드로 표현할 수 있다.

fetch(url, options)
.then((response) => console.("response:", response))
.catch((error) => console.("error:", error))

// API 호출이 성공했을 경우에는 응답 response 객체(= response:)를 resolve하고,
// 실패했을 경우에는 예외error 객체를 reject(= error:)합니다.

 

.then() / .catch 란 ?
Promise(); 내부에 resolve함수, 또는 reject함수 호출하는 구문이 있을 경우, 둘 중 하나가 실행되면고나면  then(다음), catch(오류)으로 넘어간다. 결국 비동기작업이 완료될때, resolve, reject를 호출한다.


 

vscode 에서 자주 연습해야하는 사항 : mouseover

 

vscode에서 코드 단어 위에 마우스를 올려놓으면(클릭x), 아래와 같이 그 단어 또는 함수명에 대한 정보가 뜬다.

fetch 위에 mouseover 한 결과

위를 해석해보자.

 

function fetch // fetch 라는 이름을 가진 함수다.

function fetch ( input ) : output // 항상 함수명 소괄호 안에 있는 인자는 input 이다. 또한 소괄호와 콜론 다음에 있는 아이들은 output 이다. 즉, 반환 값이다.

 

이를 적용해보면, 해석은 이러하다.

fetch 라는 이름의 함수는 input 인자로 총 2개를 받는데

(1) 첫번째로는 input 을 받고

(2) 두번째는 init을 받는다. ? 의 뜻은 들어올수도 있고 안들어올수도 있다는 뜻이다. 

그리고 반환값으로는 Promise함수를 반환한다.

 

아하, fetch() 함수는 항상 Promise() 함수를 반환하는구나!

 

.then 의 정보도 확인해보자

.then은 promise()함수의 반환값을 받고 가는 함수이기 때문에

Promise<Response>.then의 형태로 간다고 적혀있다.

input인자로 총 두개를 받는데 (1) onfulfilled (2) onrejected 이다. 근데 둘다 ?가 붙어 있는 것을 보니 받을 수도 안받을 수도 있다는 뜻으로 해석된다. 결국 반환값은 또 Promise함수이다.

 

에러를 처리하는 .catch() 도 동일하게 Promise를 반환한다. 대신 인자는 onrejected 하나를 받는다.

 

 

이렇듯,

then 메소드는 계속 Promise()를 반환하기때문에 콜백지옥에 빠질 수 있는 위험이 있다.

 

그렇기에 이를 대신할 수 있는 함수 async, await 을 쓰는 것이 더 좋을 수 있다.


이러한 Promise ~ then 보다 좀 더 간편하고, 안전하게 쓸 수 있는 문법은

 

async() 와 await() 이다.

 

2. async() 와 await() 

async

먼저 async 는 함수 앞에 위치한다.

async function f() {
  return 1;
}

 

function 앞에 async를 붙이면 해당 함수는 항상 프라미스를 반환한다. 프라미스가 아닌 값을 반환하더라도 이행 상태의 프라미스(resolved promise)로 값을 감싸 이행된 프라미스가 반환되도록 한다.

 

async 는 promise를 반환한다

 

await

자바스크립트는 await 키워드를 만나면 promise가 처리될 때까지 기다린다. promise 가 처리가 끝나면 그 후에 결과를 반환한다.

 

예를들어, 3초 후 이행되는 프라미스를 예시로 사용하여 await가 어떻게 동작하는지 살펴보면

async function f() {

  let promise = new Promise((resolve, reject) => {
    setTimeout(() => resolve("완료!"), 3000)
  });

  let result = await promise; // 프라미스가 이행될 때까지 기다림 (*)

  alert(result); // 3초 후에 "완료!"
}

f(); // 실행

 

 

예제)

더보기
async function showAvatar() {

  // JSON 읽기
  let response = await fetch('/article/promise-chaining/user.json');
  let user = await response.json();

  // github 사용자 정보 읽기
  let githubResponse = await fetch(`https://api.github.com/users/${user.name}`);
  let githubUser = await githubResponse.json();

  // 아바타 보여주기
  let img = document.createElement('img');
  img.src = githubUser.avatar_url;
  img.className = "promise-avatar-example";
  document.body.append(img);

  // 3초 대기
  await new Promise((resolve, reject) => setTimeout(resolve, 3000));

  img.remove();

  return githubUser;
}

showAvatar();

참고블로그

728x90
반응형