【问题标题】:Why does .json() return a promise?为什么 .json() 返回一个承诺?
【发布时间】:2016-09-30 00:24:26
【问题描述】:

我最近一直在搞乱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,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,您可以访问它的title 属性。 http://jsbin.com/wofulo/edit?js,output

所以我的问题是:为什么response.json 在对象字面量中返回一个promise,但如果刚刚返回则返回值?

【问题讨论】:

  • 这很有意义,因为如果响应不是有效的 JSON,response.json() 承诺可能会被拒绝。
  • 返回值是因为promise 已被解析并传递response.json() 中的值。现在该值在 then 方法中可用。
  • 请注意,尽管方法被命名为 json(),但结果不是 JSON。它返回一个用 JavaScript 对象解析的 promise,该对象是将正文文本解析为 JSON 的结果。这个对象可以是任何可以用 JSON 表示的东西——一个对象、一个数组、一个字符串、一个数字……参考:developer.mozilla.org/en-US/docs/Web/API/Body/json
  • stackoverflow.com/a/65445674/470749 是迄今为止对我最有帮助的答案。

标签: javascript asynchronous promise fetch-api


【解决方案1】:

也可以将 await 与 responce.json() 一起使用

const responce = await fetch(url);
const result = await responce.json();

也可以将 await 与 responce.json() 一起使用

【讨论】:

    【解决方案2】:

    我刚刚找到的另一个选项是:

    1. const response = fetch("url")
    2. const data = await response.json()
    3. 常量信息 = 等待数据

    信息”是最后的回应:)

    【讨论】:

      【解决方案3】:

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

      因为您会在所有标头到达后立即收到response。调用.json() 可以获得另一个尚未加载的http 响应正文的承诺。另见Why is the response object from JavaScript fetch API a promise?

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

      因为that's how promises work。从回调中返回 Promise 并让它们被采用的能力是它们最相关的特性,它使它们无需嵌套即可链接。

      你可以使用

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

      或任何其他approaches to access previous promise results in a .then() chain 在等待 json 正文后获取响应状态。

      【讨论】:

      • 似乎很奇怪,我不能只等待数据使用 Promise 返回,当它到达时将其转换为 json?或者在那种情况下,我可以只使用JSON.parse() 而不是res.json() ??
      • @Kokodoko res.json() 基本上是res.text().then(JSON.parse) 的快捷方式。两者都使用 promise 等待数据并解析 json。
      • @Bergi,嗨,对不起,我遇到了一些困惑,也就是说,通过使用 then(res=>res.json()) 我们发送另一个请求来获取 JSON?
      • @mirzhal 不,没有其他请求。它只是在读取(异步!)其余的响应。
      【解决方案4】:

      另外,帮助我理解你描述的这个特定场景的是 Promise API documentation,特别是它解释了 then 方法返回的承诺将如何根据 handler fn 返回:

      如果处理函数:

      • 返回一个值,然后返回的promise被解析为返回值作为它的值;
      • 抛出一个错误,然后返回的 promise 被拒绝,抛出的错误作为它的值;
      • 返回一个已经解析的promise,然后返回的promise会以该promise的值作为它的值来解析;
      • 返回一个已经被拒绝的promise,然后返回的promise被拒绝,该promise的值作为它的值。
      • 返回另一个待处理的promise对象,此时返回的promise的解决/拒绝将在 处理程序返回的承诺的解决/拒绝。此外,该 then 返回的 promise 的值将与 处理程序返回的承诺。

      【讨论】:

        【解决方案5】:

        除了上述答案之外,您还可以如何处理来自您的 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
        }
        

        【讨论】:

          【解决方案6】:

          这种差异是由于 Promises 的行为比fetch() 具体造成的。

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

          第二个 sn-p 也可以写成:

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

          在这个表单和你的表单中,post 的值由 response.json() 返回的 Promise 提供。


          但是,当您返回一个普通的 Object 时,.then() 认为这是一个成功的结果并立即自行解决,类似于:

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

          post 在这种情况下只是您创建的Object,它在其data 属性中包含Promise。等待该承诺兑现的过程仍未完成。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2015-11-27
            • 2019-12-26
            • 2017-06-19
            相关资源
            最近更新 更多