순수 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)로 사용되는 개체.
(좀 더 쉽게) 비동기 작업으로 전달되는 값의 컨테이너.
(좀 더더 쉽게) 미래값을 위한 컨테이너.
then()
을 이용하면 새로운 프로미스를 이어서 반환받을 수 있다)Promise는 다음 3가지 중 하나의 상태(state)를 가진다.
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');
fetch
API 액션의 결과로 돌아오는 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
이라고 보여지기 때문에 실제 데이터를 들여다보기는 어려운 상태이다.
json()
메소드는 모든 (fetch
함수가 반환해주는)Response
객체에서 사용가능한 내장함수이다.
json()
메소드 역시 비동기 함수이기 때문에 또 하나의 Promise
를 반환한다.
Body mixin의 json() 매서드는 Response 스트림을 가져와 스트림이 완료될때까지 읽는다.
이 메서드는 body 텍스트를 JSON으로 바꾸는 결과로 해결되는 promise를 반환한다.
Response
객체에 body.json()
메소드를 호출하면 위 예제에서 확인할 수 없었던 body: ReadableStream
텍스트 데이터를 JSON으로 파싱한 결과로 반환받는 Promise
가 된다.
유일하게 fetch
promise가 rejected
state가 되는 경우는 인터넷 연결이 끊겼을 때이다.
promise에서 에러핸들링(a.k.a catching the error) 하는 2가지 방법:
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!
)
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"으로 바꿔주면 된다.
본 포스팅은 아래 강의영상과 웹사이트들을 참고 및 번역하여 작성되었습니다.
잘못된 부분에 대해 알려주시면 곧바로 정정하도록 하겠습니다. 🙂
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
잘 읽었습니다.