Javascript 为什么 .json() 返回一个承诺?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/37555031/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 20:27:29  来源:igfitidea点击:

Why does .json() return a promise?

javascriptasynchronouspromisefetch-api

提问by haveacigaro

I've been messing around with the fetch()api recently, and noticed something which was a bit quirky.

我最近一直在处理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.datareturns a Promiseobject. http://jsbin.com/wofulo/2/edit?js,output

post.data返回一个Promise对象。 http://jsbin.com/wofulo/2/edit?js,输出

However if it is written as:

但是如果写成:

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

let iterator = fetch(url);

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

posthere is a standard Objectwhich you can access the title attribute. http://jsbin.com/wofulo/edit?js,output

post这是Object您可以访问 title 属性的标准。 http://jsbin.com/wofulo/edit?js,输出

So my question is: why does response.jsonreturn a promise in an object literal, but return the value if just returned?

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

回答by Bergi

Why does response.jsonreturn a promise?

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

Because you receive the responseas soon as all headers have arrived. Calling .json()gets you another promise for the body of the http response that is yet to be loaded. See also Why is the response object from JavaScript fetch API a promise?.

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

Why do I get the value if I return the promise from the thenhandler?

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

Because that's how promises work. The ability to return promises from the callback and get them adopted is their most relevant feature, it makes them chainable without nesting.

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

You can use

您可以使用

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

or any other of the approaches to access previous promise results in a .then() chainto get the response status after having awaited the json body.

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

回答by Jonathan Lonowski

This difference is due to the behavior of Promises more than fetch()specifically.

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

When a .then()callback returns an additional Promise, the next .then()callback in the chain is essentially bound to that Promise, receiving its resolve or reject fulfillment and value.

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

The 2nd snippet could also have been written as:

第二个片段也可以写成:

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

In both this form and yours, the value of postis provided by the Promise returned from response.json().

在这种形式和你的形式中, 的值post由 返回的 Promise 提供response.json()



When you return a plain Object, though, .then()considers that a successful result and resolves itself immediately, similar to:

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

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

postin this case is simply the Objectyou created, which holds a Promisein its dataproperty. The wait for that promise to be fulfilled is still incomplete.

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

回答by Gera Zenobi

Also, what helped me understand this particular scenario that you described is the Promise API documentation, specifically where it explains how the promised returned by the thenmethod will be resolved differently depending on what the handler fnreturns:

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

if the handler function:

  • returns a value, the promise returned by then gets resolved with the returned value as its value;
  • throws an error, the promise returned by then gets rejected with the thrown error as its value;
  • returns an already resolved promise, the promise returned by then gets resolved with that promise's value as its value;
  • returns an already rejected promise, the promise returned by then gets rejected with that promise's value as its value.
  • returns another pending promise object, the resolution/rejection of the promise returned by then will be subsequent to the resolution/rejection of the promise returned by the handler. Also, the value of the promise returned by then will be the same as the value of the promise returned by the handler.

如果处理函数:

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

回答by jcroll

In addition to the above answers here is how you might handle a 500 series response from your api where you receive an error message encoded in json:

除了上面的答案之外,这里是您如何处理来自您的 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
}