我最近一直在摆弄
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,但如果返回则返回值?
为什么
返回一个承诺?response.json
因为一旦所有标头到达,您就会收到
response
。调用 .json()
会为您提供另一个尚未加载的 http 响应正文的承诺。另请参阅为什么 JavaScript fetch API 的响应对象是一个承诺?.
如果我从
处理程序返回承诺,为什么我会得到该值?then
因为这就是承诺的运作方式。从回调返回 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 主体后获取响应状态。使用 await
的现代版本(在
async
函数内):
const response = await fetch(url);
const data = await response.json();
console.log(response.status, data.title);
此外,您可能想检查状态(或只是.ok
)在阅读响应之前,它可能根本不是 JSON。
fetch()
造成的。当
.then()
回调返回额外的
Promise
时,链中的下一个
.then()
回调本质上与该 Promise 绑定,接收其解析或拒绝履行和值。第二个片段也可以写成:
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
,它在其
Promise
属性中包含
data
。等待兑现的承诺仍然不完整。
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
}
文档,特别是它解释了 then
方法返回的承诺将如何根据handler fn 返回的内容以不同的方式解析:
如果处理函数:
返回一个值:p 以返回值作为其值来实现。
- 不返回任何内容:p 的值为 undefined 。
- 抛出错误:p 被拒绝,并将抛出的错误作为其值。
- 返回一个已经履行的承诺:p 得到履行,该承诺的值作为其值。
- 返回一个已经被拒绝的 Promise:p 被拒绝,并以该 Promise 的值作为其值。
- 返回另一个待处理的 Promise:p 处于待处理状态,并在该 Promise 被满足/拒绝后立即被满足/拒绝,并以该 Promise 的值作为其值。
iterator
.then(response => {
return {
data: response.json(),
status: response.status
}
})
.then(post => document.write(post.data));
;
当您使用 data: response.json()
时,您不会返回一个已解决/已拒绝的响应,该响应将是一个普通的 JS 对象或一个错误。由于 response.json() 返回一个承诺,并且在返回时您将获得已解决的状态。其中 post.data 是promise 对象。 当您编写
return response.json()
时,您可以使用返回的普通 JS 对象中的 title 属性访问已解析的响应。
json()方法可用于所有fetch()函数。 json() 方法返回一个 Promise。请记住,当返回 Promise 时,它仍然是 pending,因为它是异步的(假设数据还不存在)。因此,要使用 json() 方法获取数据 AFTER,您需要使用另一个 then() 方法,这样它只会在数据到达后返回数据。
回答你的问题,就是这样,只是这样做的方式。就像 Promise ---> Another Promise ----> data