Fetch API与XMLHttpRequest的区别

283

我知道Fetch API使用Promise,两者都允许您向服务器发起AJAX请求。

我了解到Fetch API有一些额外的功能,在XMLHttpRequest(以及基于XHR的Fetch API填充程序)中不可用。

Fetch API有哪些额外的能力?


3
虽然我不能立即回忆起来,但是有一两件事情你可以使用XHR而无法使用fetch。你说你已经阅读了fetch具有额外的功能,如果这些文章没有说明它们是什么,那么这些文章并不是很好。 - Jaromanda X
8
在使用fetch时,有两件事是无法做到的,这些在XHR中是可以的...你不能为fetch设置自己的请求超时值,也无法获取进度事件。 - Jaromanda X
4
Fetch是XMLHttpRequest的许多类型简化操作的一种方法。如果您的用例符合Fetch的功能,则可以使用它。归根结底,对于大多数人所使用的操作,XMLHttpRequest API过于繁琐。Fetch是为了提供更清晰的操作方式,不需要用库包装XMLHttpRequest使其易于使用。 - jfriend00
2
@jfriend00,那是不正确的,fetch不是一个简化的方式,而是一种更低级的方式(实际上,现在XHR已经以fetch为基础进行定义:https://xhr.spec.whatwg.org/#the-send%28%29-method)。 - Marco Castelluccio
4
@Marco - 你怎么能说 fetch(url).then(function(data) (...)); 不比使用 XMLHttpRequest 更简单呢?它可能有很多其他功能,但是对于常见的用途来说,使用它确实更简单。这确实是一个简化过的API。 - jfriend00
显示剩余3条评论
3个回答

195

使用fetch可以做的一些事情,而XHR无法做到:

  • 您可以使用缓存API与请求和响应对象一起使用;
  • 您可以执行no-cors请求,从未实现CORS的服务器获取响应。您无法直接从JavaScript访问响应主体,但是您可以将其与其他API(例如缓存API)一起使用;
  • 流式响应(使用XHR时,整个响应在内存中缓冲,使用fetch,您将能够访问低级别流)。这在所有浏览器中尚不可用,但很快就会。

使用XHR可以做到的一些事情,目前使用fetch还不能做到,但迟早会提供(请阅读此处的“Future improvements”段落:https://hacks.mozilla.org/2015/03/this-api-is-so-fetching/):

  • 中止请求(现在Firefox和Edge支持此功能,如@sideshowbarker在评论中所解释的那样);
  • 报告进度。

本文https://jakearchibald.com/2015/thats-so-fetch/包含了更详细的描述。


2
Fetch API的规范现在提供了取消功能。迄今为止,支持已在Firefox 57和Edge 16中发布。演示:https://fetch-abort-demo-edge.glitch.me/,https://mdn.github.io/dom-examples/abort-api/。而且还有Chrome和Webkit功能缺陷 https://bugs.chromium.org/p/chromium/issues/detail?id=750599,https://bugs.webkit.org/show_bug.cgi?id=174980。操作指南:https://developers.google.com/web/updates/2017/09/abortable-fetch,https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal#Examples。在Stack Overflow答案中有一个例子:https://dev59.com/U10Z5IYBdhLWcg3wyy11#47250621 - sideshowbarker
4
另一个不同之处在于,开发者工具无法重放“fetch”请求。 - Parziphal
2
而且,根据我的经验,fetch可以请求文件,但XHR不能。 - D. Pardal
3
2021年的报告显示,仍然没有办法跟踪使用“fetch”API创建的请求(或响应)的进度。如果有的话,“XMLHttpRequest”也会慢慢地痛苦死亡。 - Armen Michaeli
1
请求和响应返回的速度是否有差异,或者它们在性能上是相同的? - strix25
显示剩余2条评论

102

fetch

  • 缺少内置方法来消耗文档
  • 目前还没有设置超时的方法
  • 无法覆盖content-type响应头
  • 如果content-length响应头存在但未公开,则在流式传输期间无法确定正文的总长度
  • 即使请求已完成,也会调用信号的中止处理程序
  • 没有上传进度(支持将ReadableStream实例作为请求体的功能尚未推出
  • 不支持--allow-file-access-from-files(chromium)

XHR

  • 除非使用非标准的mozAnon标志AnonXMLHttpRequest构造函数,否则无法不发送cookie。
  • 无法返回FormData实例。
  • 没有与fetchno-cors模式相当的东西。
  • 始终遵循重定向。

22
fetch也缺少进度追踪功能。使用XHR时,您可以通过progress事件跟踪进度。 - rzr
2
无法覆盖响应的内容类型标头...这本来就是个坏主意。'内容类型'规定了应该返回什么,'后端应该将其传达给前端。实际上,内容类型应该是类型的唯一标题,因为请求的内容就应该被返回。如果你想要不同的东西,请从一个特殊的子域名等地方提供服务,这样可以将特定功能单独处理。你试图强加1%的规则到99%的人喉咙里。 - Orubel
@Knu 是的,现在我们更加先进,可以轻松自动化90%的解决方案,并将异常情况路由到不同的功能。 - Orubel
1
@rzr并不完全正确,你得到了Response#body - Knu
尽管如此,no-cors 看起来并不是那么有用。 - JamesTheAwesomeDude

24

上面的答案很好,提供了很好的见解,但我与这篇谷歌开发者博客文章中分享的观点相同,在实际应用中主要区别在于fetch返回的内置promise的方便性。

而不是编写下面这样的代码:

function reqListener() {
    var data = JSON.parse(this.responseText);
}

function reqError(err) { ... }

var oReq = new XMLHttpRequest();
oReq.onload = reqListener;
oReq.onerror = reqError;
oReq.open('get', './api/some.json', true);
oReq.send();

我们可以使用 Promise 和现代语法来清理代码并编写更简洁易读的内容

fetch('./api/some.json')
    .then((response) => {
        response.json().then((data) => { 
            ... 
        });
    })
    .catch((err) => { ... });

9
你可以将基本的 fetch 支持通过 polyfill 的方式添加到 IE 11 中。也可以在许多项目中放弃支持 IE11,因为在许多用户群体中,IE 11 的使用率现在已经低于 1%。 - Devon Holcombe
我讨厌IE,但我也不建议放弃IE支持,特别是当有polyfills时。仍然有数百万人使用IE和其他旧浏览器。就在几天前,我不得不告诉一个客户不要使用IE,因为我看到他正在使用它。当然,如果您的项目无论如何都不支持IE,那么polyfill也无济于事。 - PHP Guru
@PHPGuru 哎呀!这真让我生气。所有最新的网络技术在Internet Explorer上都无法使用。我希望人们至少能切换到Microsoft Edge!我也希望微软能发布一个“更新”,将IE浏览器完全禁用(或在允许使用之前显示提示屏幕),并告诉人们切换到其他浏览器。 - ADTC
我认为这纯粹是微软的营销手段。如果他们在已安装Edge的计算机上保留IE,那么他们的希望是人们会认为Edge是一个不同的浏览器(实际上并不是),而IE的坏名声将随之消失。唯一的区别是Edge比IE更新。但是,如果您不确保拥有最新版本的Edge,那么您使用的就跟使用IE一样了。 - PHP Guru
4
@PHPGuru 作为曾经在一个团队中工作了几年需要支持IE11的人,我可以告诉你100%的事实是,基于IE代码的Edge即使与IE11相比也大不相同且易于使用。而新的Edge浏览器基于Chromium,基本上只是Chrome的重新打包,在2020年1月发布,比您写这条评论的时间早一年。我真的觉得很奇怪,为什么人们还在重复这种关于Edge只是IE的谣言。 - ChrisM
当我写下那条评论时,我正在谈论我在Windows 10 PC上仍然拥有的旧版本Edge。结果我意识到它不支持我们现在认为理所当然的新标准、功能和安全更新,直到我确保安装了最新版本。 - PHP Guru

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接