그전에 알아둘 것
웹 페이지에서 서버가 보내는 요청 : request
서버가 보내주는 응답 : response라고 한다.
fetch함수는 서버에 request를 보내고 resposne를 받는 함수이다.
fetch('https://jsonplaceholder.typicode.com/users')
.then((response) => response.text())
→ 이걸 받아서 처리하는 코드가 필요하겠죠?
then부분이 그러한 코드. response를 받으면 .then메소드 안에있는 콜백함수가 실행된다. 이 때 이 response는 하나의 객체로 넘어오는데, 파라미터 이름은 아무거나 써도되지만 걍 response라고 쓰는 것.(res라 쓰기도)
then이라는 method는 콜백을 등록해주는 메소드임.
resposne가 서버로부터 오면 then으로 등록한 콜백이 실행되고, 실행되고 나면, 그 후에 등록한 then메소드의 콜백이 계속해서 실행됨.
이전 콜백의 리턴값은 다음 콜백으로 넘어감.
fetch함수는 비동기적으로 실행되고, promise객체를 리턴한다. 위에서의 then메소드는 fetch함수가 리턴하는 promise객체의 메소드인 것.
그렇다면 promise객체란 무엇일까?
: 어떤 작업에 대한 상태정보를 갖고있는 객체.
fetch함수는 서버에 request를보내고, response를 받는다.
⇒ 성공할수도, 실패할 수도 있음
⇒ 이러한 성공/실패 결과는 fetch함수가 리턴하는 프로미스 객체에 저장된다.
그래서 프로미스 객체를 보면 fetch함수의 결과로 성공했는지 실패했는지 알 수 있다.
: 즉, 어떤 작업에 대한 성공실패상태 , 작업의 결과를 저장하는 객체라고 이해해보장.
1→2 또는 1→3.
fetch함수에서의 작업이 성공적으로 이루어져 promise가 fulfilled상태(성공)가 된다면, promise객체는 그 작업의 성공결과도 함께 가지게된다.
= 작업성공결과.
promise객체가 rejected상태가 되면, 작업실패 이유에 대한 결과를 갖는다
= 작업실패정보
fetch('url')
.then(res ⇒ (), )
fetch함수와 함께 사용하는 콜백을 등록하는 .then메소드는 사실 Promise객체의 메소드이다!
pending → fulfilled상태가 될 때 실행할 콜백을 등록하는 메소드.(바로 실행하는게 아님)
언제 실행 되냐? fetch함수가 request보내고, response를 정상적으로 받았을때. 그때 이 콜백이 실행된다.
Promise 객체의 작업성공결과(response)는, 첫번째 콜백의 파라미터로 넘어오게 된다!!
fetch함수의 경우, 작업성공결과는 서버가 보낸 response.
프로미스 객체들을 계속해서 연결해 나간다는 뜻. 이어나가기, 연결하기.
.then
또는 .catch
, .finally
의 핸들러가 프라미스를 반환하면, 나머지 체인은 프라미스가 처리될 때까지 대기함. 처리가 완료되면 프라미스의 result
(값 또는 에러)가 다음 체인으로 전달됨.
console.log('Start!);
fetch('https://jsonplaceholder.typicode.com/users')
.then((response) => response.text())
.then((result) => {console.log(result);});
console.log('End');
then메소드 뒤에는 계~속해서 then메소드들을 붙여나갈 수 있다.
then메소드가 이어질 경우 , 이전 콜백의 리턴값을 다음 콜백의 파라미터로 넘겨받아 사용하게됨.
fetch('https://jsonplaceholder.typicode.com/users')
.then((response) => response.text())
.then((result) => {
const users = JSON.parse(result);
return user[0];
})
.then(**(user)** => {
console.log(user);
const { address } = user;//비구조화할당으로 user에서 address추출.
return address;
})
.then((**address**) => {
console.log(address);
const{ geo } = address;
return geo;
})
.then (**geo**) => {
console.log(geo);
const { lat } = geo;
return lat;
})
.then((lat) => {
console.log(lat);
});
여기서 프로미스 객체는 fetch함수의 작업결과인 response 하나라고 생각할 수 있으나,
사실 then메소드는 새로운 Promise객체를 리턴한다.(저 친구들 각각 별개의 Promise객체를 리턴중인거임)
Promise객체의 then메소드는 새로운 Promise객체를 리턴해주기 때문에, 속해서 then을 이어붙여나갈 수 있는 것!
중요한 사실,
then메소드가 return한 Promise객체는 가장처음엔 pending상태임.
나중에 then메소드로 등록한 콜백이 실행되고, 콜백에서 어떤 값을 리턴하면, then메소드가 리턴했던 Promsie객체가 영향을 받는다.
이 때, then메소드가 어떤값을 리턴하냐에 따라 받는 영향이 달라진다.
then : Promise 객체 리턴
then안에있는 콜백이 어떤 값 / Promsie객체를 리턴해
then메소드가 리턴한 Promise객체와 동일한 상태와 결과값을 가지게 된다.
→ 이 두 가지 차이점은 중요한 거라서 코드를보면서 다시 설명
응답이 완전히 종료되고, 응답 전체를 읽으려면 메서드 response.text()
를 호출해야 함. response.text()
는 원격 서버에서 전송한 텍스트 전체가 다운로드되면, 이 텍스트를 result
값으로 갖는 이행된 프라미스를 반환합니다.
fetch('https://jsonplaceholder.typicode.com/users')
.then((response) => response.text())
.then((result) => {
const users = JSON.parse(result);
return users[0];
})
.then(**(user)** => {
console.log(user);
const { address } = user;//비구조화할당으로 user에서 address추출.
return address;
})
.then((**address**) => {
console.log(address);
const{ geo } = address;
return geo;
})
.then((**geo**) => {
console.log(geo);
const { lat } = geo;
return lat;
})
.then((lat) => {
console.log(lat);
});
이런식으로 순서대로 콜백이 실행되는 것이 then메소드의 특징.
fetch로 받은 JSON데이터를 사용하기위해
fetch('https://jsonplaceholder.typicode.com/users')
.then((response) => response.text())
.then((result) => {
const users = JSON.parse(result);
// ...
});
response 객체의 text 메소드로 리스폰스의 내용을 추출(response.text();
)하고 이것을 Deserialize(JSON.parse(result);
) 하거나
(serialize: object ⇒ JSON string, deserialize: JSON string ⇒ object)
fetch('https://jsonplaceholder.typicode.com/users')
.then((response) => **response.json()**)
.then((users) => {
// ...
});
console.log('End');
response 객체의 json 메소드로 리스폰스의 내용 추출과 Deserialize를 한 번에 수행(response.json()
)할 수 있다
→ 이러한 text 메소드와 json 메소드가 Promise 객체를 리턴하는 메소드다.
fetch 함수로 리스폰스를 잘 받으면, response 객체의 text 메소드는, Promise객체를 리턴하게 됨.
: 이 Promise객체는 fulfilled 상태이면서 리스폰스의 바디에 있는 내용을 string 타입으로 변환한 값을 '작업 성공 결과'로 가짐
(문장이 조금 기니까 반복해서 읽어야함...)
이때 그 작업 성공 결과는 string 타입임. 이때 그 값이 만약 JSON 데이터라면 이전에 배운 것처럼 JSON 객체의 parse 메소드로 Deserialize를 해줘야한다!(JSON.parse(result);
)
{
"language": [
{
"name": "HTML",
"category": "web",
"developer": "W3C"
},
{
"name": "CSS",
"category": "web",
"developer": "W3C"
},
{
"name": "Java",
"category": "application",
"developer": "Oracle"
},
{
"name": "Python",
"category": "application",
"developer": "Python"
}
]
}
JSON은 JavaScript Object Notation의 약자.JSON은 사람이 읽을 수 있는 텍스트 기반의 데이터 교환 표준입니다.
이러한 JSON은 XML의 대안으로서 좀 더 쉽게 데이터를 교환하고 저장하기 위하여 고안되었습니다.
또한, JSON은 텍스트 기반이므로 어떠한 프로그래밍 언어에서도 JSON 데이터를 읽고 사용할 수 있습니다.
JSON 데이터는 이름과 값의 쌍으로 구성됩니다.
이러한 JSON 데이터는 데이터 이름, 콜론(:), 값의 순서로 구성됩니다.
"데이터이름": 값
다음 예제는 데이터의 이름이 "name"이고, 값은 "식빵"이라는 문자열을 갖는 JSON 데이터의 예제입니다.
"name": "식빵"
데이터의 이름도 문자열이므로, 항상 큰따옴표("")와 함께 입력해야 합니다.
데이터의 값으로는 다음과 같은 타입이 올 수 있습니다.
숫자(number)
문자열(string)
불리언(boolean)
객체(object)
배열(array)
NULL
fetch 함수로 리스폰스를 잘 받으면, response 객체의 json 메소드는, Promise객체를 리턴하게되는데.
: 이 Promise객체는 fulfilled상태면서 response의 body에 잇는 JSON 데이털르 자바스크립트 객체로 deserialize한 객체를 '작업성공결과'로 가짐
만약 response의 body에 있는 내용이 JSON 타입이 아니라면 에러가 발생하고 Promise 객체는 rejected 상태가 되면서 그 '작업 실패 정보'를 갖게 된다. (json메소드가 json타입을 받기때문)
→ 핵심은 response 객체의 text 메소드와 json 메소드가 Promise 객체를 리턴하는 메소드라는 사실.
위에서 배운 내용인 'then 메소드가 리턴했던 Promise 객체(A)는 그 콜백에서 리턴한 Promise 객체(B)와 동일한 상태와 결과를 갖게 된다'는 규칙과 연관지어서 생각해보자.
이 말은 곧, 콜백에서 리턴한 Promise 객체로부터 새로운 Chain이 시작된다는 말과도 같음
response 객체의 text 메소드 또는 json 메소드 이후에 등장하는 then 메소드부터는 string 타입의 값이나 자바스크립트 객체를 갖고 바로 원하는 작업을 할 수 있다.
콜백이 실행되다가 에러가 발생하는 경우가 있습니다. 예를 들어
fetch('https://jsonplaceholder.typicode.com/users')
.then((response) => {
...
add(1, 2);// ReferenceError 발생
...
});
이렇게 정의하지도 않은 함수를 콜백에서 사용해서 에러가 발생하거나
fetch('https://jsonplaceholder.typicode.com/users')
.then((response) => {
...
throw new Error('failed');
...
});
특정 경우에 인위적으로 throw 문을 써서 에러를 발생시키는 경우도 있을 것임.
이렇게 콜백이 실행되다가 에러가 발생한다면, then 메소드가 리턴했던 Promise 객체는 어떻게 될까? 이 경우에는 Promise 객체가 rejected 상태가 되고, 작업 실패 정보로 해당 에러 객체를 갖게 됨. 개발자 도구에서 실행해보면
const promise = fetch('https://jsonplaceholder.typicode.com/users')
.then((response) => { throw new Error('test'); });
promise 를 입력하여 then 메소드가 리턴한 Promise 객체의 내부를 살펴보면 이렇게 생겼는데요.
지금 [[PromiseState]]는 Promise 객체의 상태를, [[PromiseResult]]는 Promise 객체의 결과(작업 성공 결과 또는 작업 실패 정보)를 나타내는 내부 슬롯.
자세히 보면 현재 Promise 객체가 rejected 상태이고, 발생한 Error 객체를 그 작업 실패 정보로 갖고 있다는 것을 알 수 있e다.
.catch
는 프라미스에서 발생한 모든 에러를 다룬다. reject()
가 호출되거나 에러가 던져지면 .catch
에서 이를 처리합니다.
위에선 .then메소드를 사용해서 fulfilled상태가 되었을 때 실행할 콜백을 등록하는 경우만 보았는데,
rejected 상태가 될때 실행하고 싶은 콜백은 어떻게 등록하는 걸까?
fetch('https://jsonplaceholder.typicode.com/users') // Promise-A
.then(successCallback, errorCallback);
: 이렇게 then메소드의 두번째 파라미터로 넣으면된다.!
하.지.만. 다른 방법도있다.
catch메소드를 사용하는것!
Promise객체가 rejected상태가 되엇을때 실행할 콜백을 등록하는 Promise객체의 메소드.
fetch('[https://jsonplaceholder.typicode.com/users](https://jsonplaceholder.typicode.com/users)')
.then((response) => response.text())
.catch((error) => {console.log(error);})
.then((result) => {console.log(result);});
위코드를 시험해보기 위해 일부러 error를발생시켜보자 (존재하지 않는url주소를 적어보장)
코드 실행하면, catch메소드 안의 콜백이 실행되어서 에러가 콘솔에 찍힘.
(인터넷 연결 안된상황가정) ⇒ fetch결과로 rejected
fetch('https://jsonplaceholder.typicode.com/users')// Promise-A
.then((response) => response.text())// Promise-B
.then(undefined, (error) => { console.log(error); })// Promise-C
.then((result) => { console.log(result); });// Promise-D
catch 메소드는 then 메소드의 첫 번째 인자로 undefined을 넣은 것과 같기 땜에 catch 메소드를 then 메소드로 변환해서 이해해보자.
이 코드에서 fetch 함수와 각각의 then 메소드가 리턴하는 Promise 객체를 순서대로 Promise-A, B, C, D라고 하고, 그리고 각각의 Promise의 상태가 어떻게 변하는지 살펴보자.
일단 fetch 함수의 작업이 실패해서 Promise-A 객체가 rejected 상태가 되면, 첫 번째 then 메소드의 두 번째 콜백이 실행되어야 함.
첫 번째 then 메소드에는 두 번째 콜백이 없기 때문에 아무 콜백도 실행되지 X
이런 경우에는 Promise-B 객체가 Promise-A와 똑같은 rejected 상태가 되고, 동일한 작업 실패 정보를 갖게 된다.
→ 그럼 이제 rejected 상태가 된 Promise-B에 붙은 then 메소드에는 두 번째 콜백이 있기 때문에 이 두 번째 콜백이 실행됨. (즉, catch 메소드의 콜백이 실행). (rejected 상태의 Promise객체가 넘어갔기 때문에)