XMLHttpRequest VS. Fetch, 谁才是 2019 最适合的 AJAX 技术?
yuyutoo 2024-10-12 00:50 1 浏览 0 评论
原 作 者:Craig Buckler
原文链接:https://www.sitepoint.com/xmlhttprequest-vs-the-fetch-api-whats-best-for-ajax-in-2019/
注:本文是一篇译文。
XMLHttpRequest 最初是由 1999 年发布的 IE5.0 ActiveX 组件实现的,到目前为止(2019 年),刚好 20 年。
在此之前,倒是有一些办法可以在不刷新页面的情况下从服务器获取数据,但是他们通常依赖一些笨拙的技术,例如通过 <script> 注入或是一些第三方插件。微软开发了XMLHttpRequest的初始版本, 用于替代 Outlook 基于浏览器的电子邮件客户端。
直到 2006 年 XMLHttpRequest 才成为 Web 标准,但在此之前已经非常多的浏览器将其实现了。由于这项技术在 Gmail 和 Google Maps 中的广泛使用,并且 Jesse James Garrett 在 2005 年发表了一篇文章:AJAX: A New Approach to Web Applications[1]。使得这个新术语吸引了开发人员的大量关注。
从 AJAX 到 Ajax
AJAX 是 Asynchronous JavaScript and XML 的简称。"Asynchronous" 一词,理解起来很简单就是 “异步” 的意思,但是有如下 2 点,需要注意一下:
- 虽然 VBScript 和 Flash 也可以实现异步,但是 JavaScript 更为合适。
- 请求的参数格式不一定非得是 XML,尽管这在当时确实很流行。但它可以使用任何的数据格式,现如今开发者的首选,一般是 JSON。
现在,"Ajax" 一般是指在客户端向服务器获取数据并动态的更新 DOM,使得无需刷新整个页面的通用术语。“Ajax” 是大多数 Web 应用程序和单页应用程序(SPA)的核心技术。
XMLHttpRequest
以下 JavaScript 代码展示了如何使用XMLHttpRequest(通常简称为 XHR)向http://domain/service发出的 HTTP GET 请求。
let xhr = new XMLHttpRequest();
xhr.open('GET', 'http://domain/service');
// request state change event
xhr.onreadystatechange = function() {
// request completed?
if (xhr.readyState !== 4) return;
if (xhr.status === 200) {
// request successful - show response
console.log(xhr.responseText);
} else {
// request error
console.log('HTTP error', xhr.status, xhr.statusText);
}
};
// start request
xhr.send();
`XMLHttpRequest`[2]对象有许多属性、方法和事件。例如,可以设置和监测以毫秒为单位的超时:
// set timeout
xhr.timeout = 3000; // 3 seconds
xhr.ontimeout = () => console.log('timeout', xhr.responseURL);
并且 progress 事件可以报告长时间运行的文件上传:
// upload progress
xhr.upload.onprogress = p => {
console.log( Math.round((p.loaded / p.total) * 100) + '%') ;
}
属性的数量可能令人困惑,而且XMLHttpRequest的早期实现在跨浏览器之间也不一致。因此,很多库和框架都提供了 Ajax 的封装函数,例如jQuery.ajax()方法:
// jQuery Ajax
$.ajax('http://domain/service')
.done(data => console.log(data))
.fail((xhr, status) => console.log('error:', status));
Fetch
Fetch API[3]是XMLHttpRequest的现代替代方案。通用的Header[4],Request[5]和Response[6]接口提供了一致性,同时 Promises 允许更简单的的链式调用和不需要回调的 async / await。
fetch(
'http://domain/service',
{ method: 'GET' }
)
.then( response => response.json() )
.then( json => console.log(json) )
.catch( error => console.error('error:', error) );
Fetch 简洁,优雅,易于理解,并且在 PWA Service Worker 中大量使用。为什么不用它替代古老的 XMLHttpRequest 呢?
不幸的是,Web 开发从未如此明确。Fetch 还不是用于 Ajax 的完美替代品...
浏览器支持
Fetch API 在大部分浏览器中得到了很好的支持[7],但是不支持所有版本的 IE。使用 2017 年之前版本的 Chrome,Firefox 和 Safari 的人可能也会遇到问题。这些用户或许只占你用户群的一小部分......也有可能是主要客户。所以编码之前,请务必确认兼容性!
此外,与成熟的 XHR 对象相比,Fetch API 较新,并且会接收更多正在进行的更新。这些更新不太可能破坏原始代码,但预计未来几年会进行一定的维护工作。
默认无 Cookie
与XMLHttpRequest不同,Fetch 并不会默认发送 cookie,因此应用的身份验证可能会失败。可以通过更改第二个参数中传递的初始值[8]来解决此问题,例如:
fetch(
'http://domain/service',
{
method: 'GET',
credentials: 'same-origin'
}
)
错误不会被拒绝
令人惊讶的是,HTTP 错误(例如404 Page Not Found 或 500 Internal Server Error)不会导致 Fetch 返回的 Promise 标记为 reject;.catch()也不会被执行。想要精确的判断 fetch 是否成功,需要包含 promise resolved 的情况,此时再判断 response.ok是不是为 true。如下:
fetch(
'http://domain/service',
{ method: 'GET' }
)
.then( response => {
if(response.ok) {
return response.json();
}
throw new Error('Network response was not ok.');
})
.then( json => console.log(json) )
.catch( error => console.error('error:', error) );
仅当请求无法完成时才触发reject,例如网络故障或请求被阻止。这会使错误捕获更加复杂。
不支持超时
Fetch 不支持超时,只要浏览器允许,请求将继续。解决方法是可以将 Fetch 包装在一个 Promise 中,例如:
// fetch with a timeout
function fetchTimeout(url, init, timeout = 3000) {
return new Promise((resolve, reject) => {
fetch(url, init)
.then(resolve)
.catch(reject);
setTimeout(reject, timeout);
}
}
或使用Promise.race()决定 fetch 或 timeout 何时首先完成,例如:
Promise.race([
fetch('http://url', { method: 'GET' }),
new Promise(resolve => setTimeout(resolve, 3000))
])
.then(response => console.log(response))
中止 Fetch
通过xhr.abort()很容易结束一个 XHR 请求,另外也可以通过xhr.onabort函数监测事件解决。
之前一直无法中止一个 Fetch 请求,但是现在实现了AbortController API[9]的浏览器可以支持它。这将触发一个信号,该信号可以传递给 Fetch 启动对象:
const controller = new AbortController();
fetch(
'http://domain/service',
{
method: 'GET'
signal: controller.signal
})
.then( response => response.json() )
.then( json => console.log(json) )
.catch( error => console.error('Error:', error) );
Fetch 可以通过调用controller.abort()来中止。Promise 被标记 reject 后,会调用.catch()函数。
没有 Progress
在撰写本文时,Fetch 仍不支持进度事件。因此,不可能显示文件上传或大型表单提交的进度状态。
XMLHttpRequest vs Fetch?
最后,选择还是看你自己......除非你的应用是要求有上传进度条的 IE 客户端。你也可以选择将Fetch polyfill[10]与Promise polyfill[11]结合使用,以便在 IE 中执行 Fetch 代码。
对于更简单的 Ajax 调用,XMLHttpRequest是低级别的,更复杂的,并且你需要封装函数。不幸的是,一旦你开始考虑超时,中止调用和错误捕获的复杂性,Fetch 也会如此。
Fetch 的未来可期。但是,该 API 是相对较新,它不提供所有 XHR 的功能,并且某些参数设置比较繁琐。因此在以后的使用过程中,请注意上述问题。
关注我
大家好,这里是 FEHub,每天早上 9 点更新,为你分享优质精选文章,与你一起进步。
如果喜欢这篇文章,希望大家点赞,评论,转发。你的支持,是我最大的动力,咱们明天见 :)
关注 「FEHub」,每天进步一点点。
参考资料
[1]
AJAX: A New Approach to Web Applications: https://adaptivepath.org/ideas/ajax-new-approach-web-applications/
[2]
XMLHttpRequest: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest
[3]
Fetch API: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
[4]
Header: https://developer.mozilla.org/en-US/docs/Web/API/Headers
[5]
Request: https://developer.mozilla.org/en-US/docs/Web/API/Request
[6]
Response: https://developer.mozilla.org/en-US/docs/Web/API/Response
[7]
支持: https://caniuse.com/#search=fetch
[8]
初始值: https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters
[9]
AbortController API: https://developer.mozilla.org/en-US/docs/Web/API/AbortController
[10]
Fetch polyfill: https://github.github.io/fetch/
[11]
Promise polyfill: https://www.npmjs.com/package/promise-polyfill
相关推荐
- jQuery VS AngularJS 你更钟爱哪个?
-
在这一次的Web开发教程中,我会尽力解答有关于jQuery和AngularJS的两个非常常见的问题,即jQuery和AngularJS之间的区别是什么?也就是说jQueryVSAngularJS?...
- Jquery实时校验,指定长度的「负小数」,小数位未满末尾补0
-
在可以输入【负小数】的输入框获取到焦点时,移除千位分隔符,在输入数据时,实时校验输入内容是否正确,失去焦点后,添加千位分隔符格式化数字。同时小数位未满时末尾补0。HTML代码...
- 如何在pbootCMS前台调用自定义表单?pbootCMS自定义调用代码示例
-
要在pbootCMS前台调用自定义表单,您需要在后台创建表单并为其添加字段,然后在前台模板文件中添加相关代码,如提交按钮和表单验证代码。您还可以自定义表单数据的存储位置、添加文件上传字段、日期选择器、...
- 编程技巧:Jquery实时验证,指定长度的「负小数」
-
为了保障【负小数】的正确性,做成了通过Jquery,在用户端,实时验证指定长度的【负小数】的方法。HTML代码<inputtype="text"class="forc...
- 一篇文章带你用jquery mobile设计颜色拾取器
-
【一、项目背景】现实生活中,我们经常会遇到配色的问题,这个时候去百度一下RGB表。而RGB表只提供相对于的颜色的RGB值而没有可以验证的模块。我们可以通过jquerymobile去设计颜色的拾取器...
- 编程技巧:Jquery实时验证,指定长度的「正小数」
-
为了保障【正小数】的正确性,做成了通过Jquery,在用户端,实时验证指定长度的【正小数】的方法。HTML做成方法<inputtype="text"class="fo...
- jquery.validate检查数组全部验证
-
问题:html中有多个name[],每个参数都要进行验证是否为空,这个时候直接用required:true话,不能全部验证,只要这个数组中有一个有值就可以通过的。解决方法使用addmethod...
- Vue进阶(幺叁肆):npm查看包版本信息
-
第一种方式npmviewjqueryversions这种方式可以查看npm服务器上所有的...
- layui中使用lay-verify进行条件校验
-
一、layui的校验很简单,主要有以下步骤:1.在form表单内加上class="layui-form"2.在提交按钮上加上lay-submit3.在想要校验的标签,加上lay-...
- jQuery是什么?如何使用? jquery是什么功能组件
-
jQuery于2006年1月由JohnResig在BarCampNYC首次发布。它目前由TimmyWilson领导,并由一组开发人员维护。jQuery是一个JavaScript库,它简化了客户...
- django框架的表单form的理解和用法-9
-
表单呈现...
- jquery对上传文件的检测判断 jquery实现文件上传
-
总体思路:在前端使用jquery对上传文件做部分初步的判断,验证通过的文件利用ajaxFileUpload上传到服务器端,并将文件的存储路径保存到数据库。<asp:FileUploadI...
- Nodejs之MEAN栈开发(四)-- form验证及图片上传
-
这一节增加推荐图书的提交和删除功能,来学习node的form提交以及node的图片上传功能。开始之前需要源码同学可以先在git上fork:https://github.com/stoneniqiu/R...
- 大数据开发基础之JAVA jquery 大数据java实战
-
上一篇我们讲解了JAVAscript的基础知识、特点及基本语法以及组成及基本用途,本期就给大家带来了JAVAweb的第二个知识点jquery,大数据开发基础之JAVAjquery,这是本篇文章的主要...
- 推荐四个开源的jQuery可视化表单设计器
-
jquery开源在线表单拖拉设计器formBuilder(推荐)jQueryformBuilder是一个开源的WEB在线html表单设计器,开发人员可以通过拖拉实现一个可视化的表单。支持表单常用控件...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- mybatis plus (70)
- scheduledtask (71)
- css滚动条 (60)
- java学生成绩管理系统 (59)
- 结构体数组 (69)
- databasemetadata (64)
- javastatic (68)
- jsp实用教程 (53)
- fontawesome (57)
- widget开发 (57)
- vb net教程 (62)
- hibernate 教程 (63)
- case语句 (57)
- svn连接 (74)
- directoryindex (69)
- session timeout (58)
- textbox换行 (67)
- extension_dir (64)
- linearlayout (58)
- vba高级教程 (75)
- iframe用法 (58)
- sqlparameter (59)
- trim函数 (59)
- flex布局 (63)
- contextloaderlistener (56)