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
Why does .json() return a promise?
提问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.data
returns a Promise
object.
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));
;
post
here is a standard Object
which 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.json
return a promise in an object literal, but return the value if just returned?
所以我的问题是:为什么response.json
在对象文字中返回承诺,但如果刚刚返回则返回值?
回答by Bergi
Why does
response.json
return a promise?
为什么会
response.json
返回一个 promise?
Because you receive the response
as 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
then
handler?
如果我从
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 post
is 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))
);
post
in this case is simply the Object
you created, which holds a Promise
in its data
property. 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 then
method 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
}