[js] fetch와 Promise

SYhwang·2023년 2월 26일
0

fetch 함수

서버로 request를 보내고 responese를 받아오기 위해 사용하는 함수이다.
첫 번째 인자로 request를 보낼 url 주소를 사용하며, 두 번째 인자에는 method, headers, body 등을 추가적으로 지정하기 위한 옵션 객체를 사용할 수 있다.

fetch('http://ip주소:포트번호/엔드포인트', {method: "GET"})
  .then((response) => response.json())
  .then((data) => console.log(data));

fetch 와 Promise

fetch 함수의 결과물은 promise 객체가 된다. promise 객체는 작업의 상태에 대한 정보를 가진 객체이다.
작업의 상태는 진행 중(pending) 성공(fulfilled) 실패(rejected) 세 가지가 있으며, 성공 상태에서 promise 객체는 작업 성공 결과물을 추가로 가지게 되고 실패 상태에서는 작업 실패 정보를 추가로 가지게 된다.

promise 객체의 .then() 메서드를 이용하면 작업이 성공했을 때의 결과물이 첫 번째 파라미터가 된다.
fetch의 결과물은 서버에서 보내온 response 이므로, 해당 response에 담긴 JSON 데이터를 추출하기 위해 response의 .json() 메서드를 사용해 JSON데이터를 parsing 한 데이터를 리턴한다.
해당 작업이 성공하면 다음 .then()의 첫 번째 파라미터는 위에서 리턴해준 data 객체가 되므로, 해당 data를 자유롭게 사용할 수 있게 된다.

Promise chaining

프로미스 객체들을 연속적으로 chain 하는 것을 Promise chaining 이라고 한다.

  • .then 메서드 내부의 콜백 함수가 실행되고 나면 then 메서드는 콜백 함수 실행 결과에 따라 새로운 promise 객체를 리턴한다.
  • then 메서드 내부의 콜백 함수의 결과물이 promise 객체인 경우
    콜백 함수의 결과물 promise 객체의 상태와 작업 성공 결과를 then 메서드의 결과물 promise 객체 역시 그대로 가지게 된다.
  • then 메서드 내부의 콜백 함수의 결과값이 promise 객체가 아닌 경우
    then 메서드의 promise 객체는 fulfilled 상태가 되고 콜백 함수의 결과값을 작업 성공 결과로 가진 promise 객체를 리턴한다.
  • then 메서드 내부의 콜백 함수가 아무 것도 리턴하지 않는 경우
    콜백 함수가 undefined 를 리턴한 것으로 간주하며, then 메서드의 promise 객체는 fulfilled 상태가 되고 작업 성공 결과로 undefined를 가지게 된다.

따라서 콜백 함수의 결과물이 promise이든 아니든 결과적으로 then 메서드가 promise 객체를 리턴하게 되므로 앞 콜백의 결과물을 파라미터로 가지는 .then 메서드를 계속해서 체이닝 할 수 있다.

Promise chaining이 필요한 경우

promise chaining은 비동기 작업을 순차적으로 수행해야 할 때 전체 코드를 좀 더 깔끔하게 나타내기 위해서 사용한다.
콜백 안에서 계속 콜백을 호출하는 대신 콜백에서 프로미스 객체를 리턴해서 then 메서드를 체이닝 해서 깔끔하게 표현하기 위한 것이다.

fetch('http://ip주소:포트번호/유저정보 엔드포인트', {method: "GET"})
  .then((response) => response.json())
  .then((data) => {
  	const { id } = data[0]; //데이터 0번의 유저 id
  	fetch(`{base_url}/users/${id}/posts`)
	  .then((response) => response.json())
  	  .then((posts) => console.log(posts))
  })

이런 식으로 fetch 안에서 fetch를 불러오고 그 콜백으로 이어지는 대신,

fetch('http://ip주소:포트번호/유저정보 엔드포인트', {method: "GET"})
  .then((response) => response.json())
  .then((data) => {
  	const { id } = data[0]; //데이터 0번의 유저 id
  	return fetch(`{base_url}/users/${id}/posts`)
  })
  .then((response) => response.json())
  .then((posts) => console.log(posts))

프로미스 객체를 리턴하고 그 결과물을 다음 then으로 넘겨줄 수 있다.

promise 객체가 rejected 상태가 될 때

  1. then 메서드의 두 번째 인자로 작업이 실패했을 때의 콜백 함수를 넣어주면 된다.
    작업이 실패한 경우 promise 객체의 상태는 rejected가 되며, 작업 실패 정보는 Error 객체가 되는데, 두 번째 콜백 함수의 인자는 작업 실패 정보인 이 Error 객체가 들어가게 된다.
fetch('http://ip주소:포트번호/엔드포인트', {method: "GET"})
  .then((response) => response.json(), (error) => {console.log(error)})
  .then((data) => console.log(data));

2. catch 메서드 사용
위와 같이 then 메서드의 두 번째 인자는 보통 잘 사용하지 않고, 보통 catch 메서드를 사용한다.

fetch('http://ip주소:포트번호/엔드포인트', {method: "GET"})
  .then((response) => response.json())
  .then((data) => {console.log(data)});
  .catch((error) => {console.log(error)})

catch 메서드 내의 콜백은 앞 promise 객체에서 넘어온 작업 실패 정보의 에러 객체를 인자로 가지게 되는데, 사실 이는 then메서드의 변형이다. 위 코드는 아래 코드와 동일하다.

fetch('http://ip주소:포트번호/엔드포인트', {method: "GET"})
  .then((response) => response.json())
  .then((data) => {console.log(data)});
  .then(undefined, (error) => {console.log(error)})

따라서 catch 메서드가 실행되고 나면 그 결과물인 promise 객체는 fulfilled를 상태 정보로 가지며, 작업 성공 결과를 undefined로 가지게 된다.
cath 메서드 뒤의 체인에서 에러가 나는 경우 catch가 잡지 못하므로, catch 메서드는 보통 마지막 체인으로 사용한다. 중간에 error가 발생하면 그 뒤의 체인부터는 다음 체인으로 rejected 상태와 에러 객체가 계속해서 전달되므로 마지막 체인에서 catch 가 가능하다.

finally 메서드

promise 객체의 상태가 fulfilled 이든 rejected 이든 상관없이 다음에 실행하고 싶은 작업이 있다면 finally 메서드를 사용한다. finally 메서드는 보통 catch 메서드 뒤에 사용하게 되며, 콜백 함수 내에 인자를 갖지 않는다.

fetch('http://ip주소:포트번호/엔드포인트', {method: "GET"})
  .then((response) => response.json())
  .then((data) => {console.log(data)});
  .catch((error) => {console.log(error)})
  .finally(() => {console.log("코드가 모두 실행되었습니다")})

0개의 댓글