Javascript 为什么这些获取方法是异步的?

Javascript 为什么这些获取方法是异步的?,javascript,fetch,Javascript,Fetch,Fetch是用于发出网络请求的基于Promise的新API: fetch('https://www.everythingisawesome.com/') .then(response => console.log('status: ', response.status)); 这对我来说是有意义的——当我们发起一个网络呼叫时,我们会返回一个承诺,让我们的线程继续处理其他业务。当响应可用时,承诺中的代码将执行 但是,如果我对响应的有效负载感兴趣,我会通过响应的方法而不是属性来实现: a

Fetch是用于发出网络请求的基于Promise的新API:

fetch('https://www.everythingisawesome.com/')
  .then(response => console.log('status: ', response.status));
这对我来说是有意义的——当我们发起一个网络呼叫时,我们会返回一个承诺,让我们的线程继续处理其他业务。当响应可用时,承诺中的代码将执行

但是,如果我对响应的有效负载感兴趣,我会通过响应的方法而不是属性来实现:

  • arrayBuffer()
  • blob()
  • formData()
  • json()
  • 正文()
这些方法回报了承诺,我不清楚为什么

fetch('https://www.everythingisawesome.com/') //IO bound
  .then(response => response.json()); //We now have the response, so this operation is CPU bound - isn't it?
  .then(entity => console.log(entity.name));

为什么处理响应的有效负载会返回一个承诺-我不清楚为什么它应该是一个异步操作。

,因为在您开始阅读内容之前,内容不会被传输。头首先出现。

查看实现获取
json
的操作是CPU限制的,因为响应承诺完成后,响应以及主体的创建就完成了。请参阅

话虽如此,我认为这主要是一个设计概念,因此您可以链接承诺处理程序,并且只使用一个启动的错误处理程序,无论错误发生在哪个阶段

像这样:

fetch('https://www.everythingisawesome.com/')
  .then(function(response) {
    return response.json()
  })
  .then(function(json) {
    console.log('parsed json', json)
  })
  .catch(function(ex) {
    console.log('parsing or loading failed', ex)
  })

已经解决的承诺的创建是以相当低的开销实现的。最后,这里不需要使用承诺,但它可以使代码更美观,并且可以编写。至少在我看来。

在阅读了fetch的实现之后,使用承诺似乎有几个原因。对于初学者来说,
json()
依赖于
FileReader
将响应blob转换为文本<在
onload
回调之前,无法使用code>FileReaders,因此承诺链就是从这里开始的

function fileReaderReady(reader) {
  return new Promise(function(resolve, reject) {
    reader.onload = function() {
      resolve(reader.result)
    }
    reader.onerror = function() {
      reject(reader.error)
    }
  })
}
在此基础上,使用额外的承诺来封装可能发生的特定错误,并将其传播给调用方。例如,如果之前已经读取过一次主体,如果blob没有转换为文本,如果文本没有转换为JSON,则可能会发生错误。承诺在这里是方便的,因为这些不同的错误中的任何一个都将简单地结束在调用方的catch块中

综上所述,基于承诺的api用于读取fetch响应,因为: 1.它们依赖于
文件读取器
,该读取器必须异步初始化自身。 2.fetch希望传播在读取正文时可能发生的各种错误。承诺允许以统一的方式实现这一点

为什么这些获取方法是异步的

天真的答案是

  • 调用
    arrayBuffer()
    方法时,必须返回使用arrayBuffer运行的结果
  • 调用
    blob()
    方法时,必须返回使用blob运行的结果
  • 调用
    formData()
    方法时,必须返回使用formData运行的结果
  • 调用
    json()
    方法时,必须返回使用json运行的结果
  • 调用
    text()
    方法时,必须返回使用文本运行的结果
当然,这并不能真正回答这个问题,因为它留下了一个悬而未决的问题:“规范为什么这么说?”

这就是它变得复杂的地方,因为我对推理有把握,但我没有官方来源的证据来证明这一点。我将尽我所能解释理性,但要知道,在这里之后的一切都应该被视为外部意见


当您使用fetch API从资源请求数据时,您必须等待资源完成下载,然后才能使用它。这应该是相当明显的。JavaScript使用异步API来处理此行为,以便所涉及的工作不会阻止其他脚本,更重要的是,不会阻止UI

资源下载完成后,数据可能会非常庞大。没有任何东西可以阻止您请求超过50MB的单一JSON对象

如果试图同步解析50MB的JSON,您认为会发生什么?它将阻止其他脚本,更重要的是阻止UI

其他程序员已经解决了如何以高效的方式处理大量数据:流。在JavaScript中,流是使用异步API实现的,这样它们就不会阻塞,如果您阅读了详细信息,那么很明显流是用来解析数据的:

若body为非null,则将stream设为body的流,否则设为空的ReadableStream对象

现在,规范可能已经定义了两种访问数据的方法:一种是用于较小数据量的同步API,另一种是用于较大数据量的异步API,但这会导致混淆和重复


此外。可以用同步代码表示的所有内容都可以用异步代码表示。事实并非如此。因此,创建了一个可以处理所有用例的异步API。

不要相信这是真的。如果省略除初始提取之外的所有内容-
fetch('http://localhost:22898/api/values');-我仍然可以通过电线获得有效载荷。响应头和负载不是逐段传递的。这取决于请求。如果发出head请求,则根本不会得到有效负载。假设您正在请求一个大文件。标题首先返回内容的详细信息。在建立tls级别等方面也可能有很多来回。看看底层的http协议。嗯,在协调跨源请求时,听起来也与
选项相关。因此,如果fetch操作由HEAD和GET组成,那么我在这里读的是哪些响应头:
。然后(response=>printOut(response.headers))
?cod