XMLHttpRequest()로 데이터를 받아 온 방식에서 Fetch API를 활용하는 방식으로 변환하면서 설명한다.
XMLHttpRequest() 방식으로 랜덤 글자 생성 링크에서 데이터를 받아오고, 그것을 출력하는 코드
const getPuzzle = (wordCount) => new Promise((resolve, reject) => { const request = new XMLHttpRequest() request.addEventListener('readystatechange', (e) => { if (e.target.readyState === 4 && e.target.status === 200) { const data = JSON.parse(e.target.responseText) resolve(data.puzzle) //(에러, 데이터) } else if (e.target.readyState === 4) { reject('An error has taken place') } }) request.open('GET', `http://puzzle.mead.io/puzzle?wordCount=${wordCount}`) request.send() }) getPuzzle('2').then((puzzle) => { console.log(puzzle) }, (err) => { console.log(`Error: ${err}`) })
fetch() 방식으로 데이터를 받아온 후 출력하는 코드
fetch('http://puzzle.mead.io/puzzle', {}).then((response) => { if (response.status === 200) { return response.json() //.json() method takes the response body and parse it as JSON } else { throw new Error('Unable to fetch puzzle') //if we manually throw error, catch() is fired } }).then((data) => { //.then() is going to access to the data, and then we can do something with parced JSON, for example console.log() console.log(data.puzzle) }).catch((error) => { console.log(error) })
Fetch API is a second way we can make http requests in newer versions of js, this new API has promises built-in, which XMLHttpRequest() doesnt support
Fetch API는 자바스크립트의 이전 버전에서 폭넓게 쓰이던 XMLHttpRequest()의 업그레이드 버전이며, 이 자체로 프로미스 형태다. 데이터 요청할 때 쓰인다.
We can access to the Fetch API by fetch() with an argument: url (, optional additional argument)
fetch()에 인자로 원하는 데이터의 경로 url을 쓴다.
Fetch returns a promise, so we can wait for this promise to resolve or reject with data we requested
Dont have to worry about readystate, cus this promise(fetch()) is going to resolve or reject only when it's ready for us. no worry about IF it's completed, just worry about HOW it's completed(400, 500, etc)
XMLHttpRequest()과 달리 readystate에 신경쓰지 않아도 된다. fetch는 프로미스이기 때문에 애초에 resolve된 결과만 보여주기 때문. 즉 응답이 돌아왔는지 안 돌아왔는지 여부가 중요한 게 아니라, 어떻게 돌아왔는지(에러코드 400 500대 등)만 신경쓰면 된다.
위의 fetch() 방식으로 작성한 코드를 분리해서, 앱 실행에 적합한 방식으로 다시 작성해보면
const getPuzzle = (wordCount) => { return fetch(`http://puzzle.mead.io/puzzle?wordCount=${wordCount}`).then((response) => { if (response.status === 200) { return response.json() } else { throw new Error('Unable to fetch puzzle') } }).then((data) => { return data.puzzle }) }
getPuzzle('2').then((puzzle) => { console.log(puzzle) }).catch((err) => { console.log(`Error: ${err}`) })
Only leave last .then() and last .catch() call. we dont want fetch() thing everytime we call getPuzzle().
마지막 .then()과 .catch() 메서드만 남기고 나머지 복잡한 코드를 분리했다. (유지보수의 용이성을 위해)
We need a promise to come back cuz we're using .then() , so we can call getPuzzle('2').then() like this
마지막 .then()을 붙이기 위해 getPuzzle()은 프로미스 형태여야 한다. 따라서 위의 복잡한 코드 부분에서 프로미스 형태인 fetch() 자체를 리턴해서 getPuzzle().then()과 같이 연결했다.
복잡한 코드는 다른 파일로 분리하고 실행에 필요한 최소한만 남기기.
const getPuzzle = (wordCount) => { return fetch(...) } getPuzzle('2').then(...)
아래와 같이 response.json()으로 나온 결과에 바로 .then()을 붙여 프로미스 체인 만들면 된다.
fetch(`http://puzzle.mead.io/puzzle?wordCount=${wordCount}`).then((response) => { if (response.status === 200) { return response.json() } else { throw new Error('Unable to fetch puzzle') } }).then((data) => { return data.puzzle })
예를 들어 이렇게 .then() 결과값으로 프로미스로 반환되지 않는 경우에도 에러가 발생하지 않는다.
getDataPromise(10).then((data) => { return getDataPromise(data) }).then((data) => { // return getDataPromise(data) return 'This is some test data' }).then((data) => { console.log(data) }).catch((err) => { console.log(err) }) //This is some test data