.json ()이 프라 미스를 반환하는 이유는 무엇입니까?


115

나는 fetch()최근에 API를 엉망으로 만들고 약간 기발한 것을 발견했습니다.

let url = "http://jsonplaceholder.typicode.com/posts/6";

let iterator = fetch(url);

iterator
  .then(response => {
      return {
          data: response.json(),
          status: response.status
      }
  })
  .then(post => document.write(post.data));
;

post.dataPromise객체를 반환 합니다. http://jsbin.com/wofulo/2/edit?js,output

그러나 다음과 같이 작성된 경우 :

let url = "http://jsonplaceholder.typicode.com/posts/6";

let iterator = fetch(url);

iterator
  .then(response => response.json())
  .then(post => document.write(post.title));
;

post여기 Object에 제목 속성에 액세스 할 수 있는 표준 이 있습니다. http://jsbin.com/wofulo/edit?js,output

그래서 내 질문은 : 왜 response.json객체 리터럴에서 약속을 반환하지만 방금 반환되면 값을 반환합니까?


1
이는 response.json()응답이 유효한 JSON이 아닌 경우 약속이 거부 될 수 있다고 생각할 때 의미 가 있습니다.
ssube

1
response.json ()에 값을 전달하여 promise가 해결 되었기 때문에 값이 반환됩니다. 이제 값을 then 메소드에서 사용할 수 있습니다.
Jose Hermosilla Rodrigo

답변:


167

response.json약속을 반환하는 이유는 무엇 입니까?

response모든 헤더가 도착하자마자 수신하기 때문입니다. 호출 .json()은 아직로드되지 않은 http 응답 본문에 대한 또 다른 약속을 제공합니다. JavaScript fetch API의 응답 객체가 약속 인 이유 도 참조하세요 . .

then핸들러 에서 프라 미스를 반환하면 왜 값을 얻 습니까?

그것이 약속이 작동하는 방식 이기 때문 입니다. 콜백에서 프라 미스를 반환하고이를 채택하는 기능은 가장 관련성이 높은 기능이며 중첩없이 체인화 할 수 있습니다.

당신이 사용할 수있는

fetch(url).then(response => 
    response.json().then(data => ({
        data: data,
        status: response.status
    })
).then(res => {
    console.log(res.status, res.data.title)
}));

또는 이전 약속에 액세스 하는 다른 접근 방식 은 json 본문을 기다린 후 응답 상태를 얻기 위해 .then () 체인 을 발생시킵니다.


Promise를 사용하여 데이터가 반환 될 때까지 기다릴 수 없으며 도착하면 json으로 변환하는 것이 이상해 보입니다. 아니면 아마도 그 경우에는 JSON.parse()대신 사용할 수 res.json()있습니까 ??
Kokodoko 2017.11.17

8
@Kokodoko는 res.json()기본적으로 res.text().then(JSON.parse). 둘 다 약속을 사용하여 데이터를 기다리고 json을 구문 분석합니다.
Bergi

@Bergi, 안녕하세요, 혼란스러워서 죄송합니다. 즉, then (res => res.json ())을 사용하여 JSON을 얻기 위해 다른 요청을 보냅니다.
mirzhal

1
@mirzhal 아니요, 다른 요청이 없습니다. 나머지 응답을 (비동기 적으로!) 읽는 것입니다.
Bergi 19

14

이 차이는 fetch()특히 약속의 동작 때문 입니다.

.then()콜백이 추가 반환 Promise, 다음 .then()체인의 콜백은 본질적으로, 그 약속에 바인딩의 결의를 수신하거나 이행과 가치를 거부합니다.

두 번째 스 니펫은 다음과 같이 작성할 수도 있습니다.

iterator.then(response =>
    response.json().then(post => document.write(post.title))
);

이 양식과 귀하의 양식 모두에서의 값은 post에서 반환 된 Promise에 의해 제공됩니다 response.json().


Object하지만 plain을 반환하면 다음 .then()과 유사하게 성공적인 결과를 고려하고 즉시 해결됩니다.

iterator.then(response =>
    Promise.resolve({
      data: response.json(),
      status: response.status
    })
    .then(post => document.write(post.data))
);

post이 경우는 단순히 Object당신이 만든 것이며 Promise, 그 data속성 을 유지 합니다. 그 약속이 성취되기를 기다리는 것은 아직 불완전합니다.


7

또한 설명하신이 특정 시나리오를 이해하는 데 도움이 된 것은 Promise API 문서입니다 . 특히 then메서드에서 반환 된 promise처리기 fn이 반환 하는 내용에 따라 다르게 해결 되는 방법을 설명 합니다.

핸들러 함수 :

  • 값을 반환하고, 반환 된 promise는 반환 된 값을 값으로 사용하여 해결됩니다.
  • 오류가 발생하면 반환 된 promise는 해당 값으로 오류가 발생하여 거부됩니다.
  • 이미 해결 된 promise를 반환하고, 그때 반환 된 promise는 해당 promise의 값을 값으로 사용하여 해결됩니다.
  • 이미 거부 된 약속을 반환하고, 반환 된 약속은 해당 약속의 값을 값으로 사용하여 거부됩니다.
  • 또 다른 보류중인 promise 객체를 반환합니다. 그때까지 반환 된 promise의 해결 / 거부는 핸들러가 반환 한 promise의 해결 / 거부 이후입니다. 또한 그때 반환 된 promise의 값은 핸들러가 반환 한 promise의 값과 동일합니다.

5

위의 답변 외에도 json으로 인코딩 된 오류 메시지를 수신하는 API에서 500 시리즈 응답을 처리하는 방법이 있습니다.

function callApi(url) {
  return fetch(url)
    .then(response => {
      if (response.ok) {
        return response.json().then(response => ({ response }));
      }

      return response.json().then(error => ({ error }));
    })
  ;
}

let url = 'http://jsonplaceholder.typicode.com/posts/6';

const { response, error } = callApi(url);
if (response) {
  // handle json decoded response
} else {
  // handle json decoded 500 series response
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.