为什么 .json() return 是一个承诺?

Why does .json() return a promise?

我最近一直在摆弄 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 return 是一个 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 return 是对象字面量中的承诺,但 return 只是 returned 的值?

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

当一个 .then() 回调 return 是一个额外的 Promise 时,链中的下一个 .then() 回调基本上绑定到该 Promise,接收它的 resolve 或 reject成就感和价值。

第二个片段也可以写成:

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

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


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

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

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

Why does response.json return a promise?

因为您会在 headers 全部到达后立即收到 response。调用 .json() 会给你另一个尚未加载的 http 响应的 body 的承诺。另见 Why is the response object from JavaScript fetch API a promise?.

Why do I get the value if I return the promise from the then handler?

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

您可以使用

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 body.

后获取响应状态

除了上述答案之外,这里还介绍了如何处理来自 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 documentation 帮助我理解了您描述的这个特定场景,特别是它解释了 then 方法返回的 promised 将如何被解析取决于 处理程序 fn returns:

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.

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

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

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

json() 方法可用于所有 fetch() 函数。 json() 方法 return 是一个 Promise。请记住,当 returning 一个 Promise 时,它仍然是 pending 因为它是异步的(假设数据还没有)。所以要使用 json() 方法获取数据 AFTER ,你需要使用另一个 then() 方法,因此它只会 return 数据到达后。

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

就像 Promise ---> 另一个 Promise ----> 数据