[JavaScript] Promise 알아보기

Dico·2020년 12월 18일
0

[JavaScript]

목록 보기
13/21

Promise와 fetch API

순수 JavaScript로 비동기통신을 하는 것은 어렵고 비효율적이다.
특히 XMLHttpRequest()를 사용해서 원하는 기능을 모두 구현하는 것은 매우 복잡하며, XMLHttpRequest()Promise객체를 함께 사용하는 것도 쉬운 일이 아니다.
XMLHttpRequest() 대신 ES6의 fetch API를 사용하면 편리하다.

// XMLHttpRequest()을 사용한 아래 코드는 
const request = new XMLHttpRequest();
request.open('GET', 'https://restcountries.eu/rest/v2/name/portugal');

// 'fetch'로 대체할 수 있다.
const request = fetch('https://restcountries.eu/rest/v2/name/portugal');

fetch API는 자체적으로Promise객체를 리턴하기 때문이다.

Promise란?
ES6문법으로, 비동기 작업의 향후 결과에 대한 자리표시자(Placeholder)로 사용되는 개체.
(좀 더 쉽게) 비동기 작업으로 전달되는 값의 컨테이너.
(좀 더더 쉽게) 미래값을 위한 컨테이너.

Promise를 쓰는 이유

  1. 비동기 결과를 처리하기 위해 비동기 함수에 전달 된 이벤트와 콜백에 의존 할 필요가 없어진다.
  2. 콜백헬(callback hell) 탈출❗️
    콜백을 중첩해서 호출하는대신, 연속적으로 비동기작업을 chaining 할 수 있게 된다.
    (then()을 이용하면 새로운 프로미스를 이어서 반환받을 수 있다)

Promise의 state 3가지

Promise는 다음 3가지 중 하나의 상태(state)를 가진다.

  1. 대기(pending): 이행하거나 거부되지 않은 초기 상태.
  2. 이행(fulfilled): 연산이 성공적으로 완료됨.
  3. 거부(rejected): 연산이 실패함.
  • +Plus: 대기 상태가 아니고, 이행(fulfilled) 또는 거부(rejected)됐을 때는 처리(settled)됐다고 말한다.

then()

then()메소드에는 promise가 fulfilled되었다고 가정하고 그 이후에 호출해야할 콜백함수를 기재한다.
then()은 연속적으로 쓰일 수 있다.(= chaining)
then()실제로 리턴값이 있든 없든 항상 promise를 반환한다.
여기서 설정해주는 리턴값은 promise의 fulfilled value가 된다.

//ex.
const getCountryData = function(country) {
    fetch(`https://restcountries.eu/rest/v2/name/${country}`)
    .then(response => response.json())  //여기서 새로운 프로미스를 반환받는다. 다음 콜백에서 data인자로 전달된다.
    .then(data => renderCountry(data[0]));
};
getCountryData('portugal');

Response객체와 body

fetchAPI 액션의 결과로 돌아오는 Response객체는,
body컨텐츠를 정의하고 핸들링할 수 있게 하는 여러가지 메소드들을 갖고 있다.
아래의 코드로 브라우저의 console창에서Response객체를 조회해보면,

const getCountryData = function(country) {
    fetch(`https://restcountries.eu/rest/v2/name/${country}`).then(function(response){
        console.log(response); 📍
    });
};
getCountryData('portugal');

다음과 같이 Response객체를 확인해 볼 수 있다.

다만 ReadableStream이라고 보여지기 때문에 실제 데이터를 들여다보기는 어려운 상태이다.

body.json()

json()메소드는 모든 (fetch함수가 반환해주는)Response객체에서 사용가능한 내장함수이다.
json()메소드 역시 비동기 함수이기 때문에 또 하나의 Promise를 반환한다.

Body mixin의 json() 매서드는 Response 스트림을 가져와 스트림이 완료될때까지 읽는다.
이 메서드는 body 텍스트를 JSON으로 바꾸는 결과로 해결되는 promise를 반환한다.

Response객체에 body.json()메소드를 호출하면 위 예제에서 확인할 수 없었던 body: ReadableStream 텍스트 데이터를 JSON으로 파싱한 결과로 반환받는 Promise가 된다.

Promise의 error handling

유일하게 fetch promise가 rejected state가 되는 경우는 인터넷 연결이 끊겼을 때이다.
promise에서 에러핸들링(a.k.a catching the error) 하는 2가지 방법:

1. then()메소드에 2nd 콜백함수 전달하기

then()메소드의 2번째 인자로 에러 시 실행되어야 할 콜백함수를 전달한다.

//ex.
fetch(`https://restcountries.eu/rest/v2/name/${country}`)
    .then(
        response => response.json(),     //fulfilled 되었을 때 
        err => alert(err) 		 //rejected 되었을 때: catching the error!  
    ) 

2. catch()메소드 사용하기

then()메소드가 끝나는 곳에 catch() 메소드를 이어서 사용한다.
catch() 메소드는 여러 번 반복되는 promise chain에서 유용하게 쓰인다. 모든 then()메소드에 2번째 인자를 전달할 필요 없이 단 한번만 error handling 코드를 기재하면 되기 때문이다.
catch() 는 promise chain 중 어디에서 에러가 발생하더라도 에러핸들링을 할 수 있게 해준다.

fetch(`https://restcountries.eu/rest/v2/name/${country}`)
    .then(response => response.json())  //여기서 새로운 프로미스를 반환받는다. 다음 콜백에서 data인자로 전달된다.
    .then(data => {
        renderCountry(data[0])
        const neighbour = data[0].borders[0];
        if (!neighbour) return;

        return fetch(`https://restcountries.eu/rest/v2/alpha/${neighbour}`);
    })
    .then(response => response.json())
    .then(data => renderCountry(data, 'neighbour'))
    .catch(err => alert(err)); 📍

+TIP: 에러핸들링을 테스트 해보려면 브라우저 dev tool에서 Network설정을 아래 화면과 같이 "Offline"으로 바꿔주면 된다.


Reference

본 포스팅은 아래 강의영상과 웹사이트들을 참고 및 번역하여 작성되었습니다.
잘못된 부분에 대해 알려주시면 곧바로 정정하도록 하겠습니다. 🙂
https://www.udemy.com/course/the-complete-javascript-course/learn/lecture/22649313#overview
https://webisfree.com/2019-05-15/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-fetch-api-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0
https://developer.mozilla.org/ko/docs/Web/API/Body/json
Promise에 대한 친절한 설명보기: 자바스크립트 개발자라면 알아야 할 33가지 개념 #25 자바스크립트 : 바보를 위한 Promise

profile
프린이의 코묻은 코드가 쌓이는 공간

1개의 댓글

comment-user-thumbnail
2023년 10월 25일

잘 읽었습니다.

답글 달기