为什么 .json() 返回一个Promise?

IT技术 javascript asynchronous promise fetch-api
2021-01-26 15:02:11

我最近一直在处理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.data返回一个Promise对象。 http://jsbin.com/wofulo/2/edit?js,输出

但是如果写成:

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您可以访问 title 属性的标准。 http://jsbin.com/wofulo/edit?js,输出

所以我的问题是:为什么response.json在对象文字返回Promise,但如果刚刚返回则返回值?

6个回答

为什么会response.json返回一个 promise?

因为您会在response所有标头到达后立即收到调用.json()为尚未加载的 http 响应正文提供了另一个Promise。另请参阅为什么来自 JavaScript fetch API 的响应对象是一个Promise?.

如果我从then处理程序返回Promise,为什么我会得到值

因为这就是 Promise 的工作方式从回调中返回 promise 并让它们被采用的能力是它们最相关的特性,它使它们无需嵌套即可链接。

您可以使用

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

或任何其他访问先前Promise方法都会导致 .then() 链在等待 json 正文后获取响应状态。

@Kokodokores.json()基本上是res.text().then(JSON.parse). 两者都使用Promise等待数据并解析 json。
2021-03-17 15:02:11
@Bergi,嗨,对不起,我遇到了一些困惑,也就是说,通过使用 then(res=>res.json()) 我们发送另一个请求来获取 JSON?
2021-03-21 15:02:11
我不能等待数据使用 Promise 返回,当它到达时将其转换为 json,这似乎很奇怪?或者也许在那种情况下我可以使用JSON.parse()而不是res.json()??
2021-04-01 15:02:11
@mirzhal 不,没有其他要求。它只是读取(异步!)响应的其余部分。
2021-04-05 15:02:11

这种差异更多是由于 Promises 的行为造成的fetch()

.then()回调返回一个额外的Promise.then()链中的下一个回调本质上绑定到那个 Promise,接收它的 resolve 或 reject 实现和值。

第二个片段也可以写成:

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属性中包含 a 等待兑现的Promise仍未完成。

此外,帮助我理解你描述的这个特定场景的是 Promise API文档,特别是它解释了then方法返回的Promise将如何根据处理程序 fn返回的内容进行不同的解析

如果处理函数:

  • 返回一个值, then 返回的 promise 以返回值作为其值进行解析;
  • 抛出错误, then 返回的Promise被拒绝,抛出的错误作为其值;
  • 返回一个已经解决的Promise,然后返回的Promise以该Promise的值作为其值得到解决;
  • 返回一个已经被拒绝的Promise, then 返回的Promise被拒绝,该Promise的value作为其value。
  • 返回另一个挂起的Promise对象, then 返回的Promise的解决/拒绝将在处理程序返回的Promise的解决/拒绝之后。此外, then 返回的Promise值将与处理程序返回的Promise值相同。

除了上面的答案之外,这里是您如何处理来自您的 api 的 500 系列响应,您会收到一条以 json 编码的错误消息:

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
}

const getJSON = function (url, errorMsg = "Something went wrong") {
  return fetch(url).then(response => {
    if (response.ok) {
      return response.json();
    }
    throw new Error(errorMsg+". Error Code: "+response.status);
  }).then(data => console.log(data));
}


getJSON("https://api.github.com/users", "you can provide error msg here.");

如果您有新问题,请点击提问按钮进行提问如果有助于提供上下文,请包含指向此问题的链接。-来自评论
2021-03-22 15:02:11