我最近一直在摆弄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));
;

职位。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是一个标准的对象,你可以访问它的title属性。 http://jsbin.com/wofulo/edit?js,output

所以我的问题是:为什么反应。Json返回一个承诺在一个对象字面量,但返回值如果刚刚返回?


当前回答

为什么会反应。Json返回承诺?

因为当所有的报头到达时,您就会收到响应。调用.json()会为尚未加载的http响应正文提供另一个承诺。参见为什么从JavaScript获取API的响应对象是一个承诺?。

如果我从当时的处理程序返回承诺,为什么我得到这个值?

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

你可以使用

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正文后获得响应状态。

其他回答

json()方法可用于所有fetch()函数。json()方法返回一个Promise。请记住,当返回Promise时,它仍然是挂起的,因为它是异步的(假设数据还不存在)。因此,要在使用json()方法之后获取数据,您需要使用另一个then()方法,以便它在到达后返回数据。

回答你的问题,就是这样,就是这样做的方式。

它就像承诺->另一个承诺---->数据

这种差异主要是由于Promises的行为而不是fetch()。

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

第二段也可以写成:

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

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


然而,当你返回一个普通对象时,.then()认为这是一个成功的结果,并立即解析自己,类似于:

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

在本例中,post只是您创建的对象,它的data属性中包含一个Promise。对实现这一承诺的等待仍未完成。

为什么会反应。Json返回承诺?

因为当所有的报头到达时,您就会收到响应。调用.json()会为尚未加载的http响应正文提供另一个承诺。参见为什么从JavaScript获取API的响应对象是一个承诺?。

如果我从当时的处理程序返回承诺,为什么我得到这个值?

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

你可以使用

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正文后获得响应状态。

除了上面的答案,这里还有你如何处理来自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
}

此外,帮助我理解你所描述的这个特定场景的是Promise API文档,特别是它解释了then方法返回的promises将如何根据处理程序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.