XMLHttpRequest VS. Fetch, 谁才是 2019 最适合的 AJAX 技术?
xsobi 2025-01-08 18:16 1 浏览
原 作 者: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
相关推荐
- 全网最详细解决Windows下Mysql数据库安装后忘记初始root 密码方法
-
一、准备重置root的初始化密码Win+R键启动命令输入窗口;输入cmd打开命令执行窗口;##界面如下##输入命令:netstopmysqld#此操作会停止当前运行的...
- Spring Boot数据库密码加密的配置方法
-
前言由于系统安全的考虑,配置文件中不能出现明文密码的问题,本文就给大家详细介绍下springboot配置数据库密码加密的方法,下面话不多说了,来一起看看详细的介绍吧...
- Mysql 8.4数据库安装、新建用户和数据库、表单
-
1、下载MySQL数据库yuminstall-ywgetperlnet-toolslibtirpc#安装wget和perl、net-tools、libtirpcwgethtt...
- mysql5.7安装教程
-
首先下载mysql的rpm包wgethttps://mirrors.ustc.edu.cn/mysql-ftp/Downloads/MySQL-5.7/mysql-community-client...
- MySQL管理授权和数据库的备份和还原详解
-
一般管理用户和授权由DBA去执行,DBA为数据库管理员一、管理用户1.添加用户...
- 数据库迁移有什么技巧?|分享强大的database迁移和同步工具
-
概述DBConvertStudio是一款强大的跨数据库迁移和同步软件,可在不同数据库格式之间转换数据库结构和数据。它将成熟、稳定、久经考验的DBConvert和DBSync核心与改进的现代...
- Mysql解压版安装过程
-
Mysql是目前软件开发中使用最多的关系型数据库,具体安装步骤如下:第一步:Mysql官网下载最新版(mysql解压版(mysql-5.7.17-winx64)),Mysql官方下载地址为:https...
- MySQL5.7升级到8.0过程详解
-
前言:不知不觉,MySQL8.0已经有好多个GA小版本了。目前互联网上也有很多关于MySQL8.0的内容了,MySQL8.0版本基本已到稳定期,相信很多小伙伴已经在接触8.0了。本篇文章主要介绍从5....
- 10种常见的MySQL错误,你可中招?
-
【51CTO.com快译】如果未能对MySQL8进行恰当的配置,您非但可能遇到无法顺利访问、或调用MySQL的窘境,而且还可能给真实的应用生产环境带来巨大的影响。本文列举了十种MySQL...
- 忘记MySQL密码怎么办?一招教你搞定
-
在安装完MySQL或者是在使用MySQL时,最尴尬的就是忘记密码了,墨菲定律也告诉我们,如果一件事有可能出错,那么它一定会出错。那如果我们不小心忘记了MySQL的密码,该如何处理呢?别着急...
- Windows 安装解压版本的 MySql
-
1、下载解压版本的MySql到https://downloads.mysql.com/archives/community/网站,根据自己需要安装的版本进行选择下载,这里下载不要选择MSII...
- 爆破SSH/MySQL账户竟如此简单
-
友情提示:初入安全,小白一个,本文重在学习与经验分享!背景使用Kali自带的MSF工具对SSH的账号密码进行爆破。1.实验环境本次实验通过MSF,可直接对SSH的账号密码进行爆破。KaliIP:1...
- Mysql8忘记密码/重置密码
-
Mysql8忘记密码/重置密码UBUNTU下Mysql8忘记密码/重置密码步骤如下:先说下大概步骤:修改配置文件,使得用空密码可以进入mysql。然后置当前root用户为空密码。再次修改配置文件,不能...
- wamp查看MySQL密码 MySQL console输入密码闪退 重置mysql密码
-
wampserver的MySQL数据库用户名为root初始密码为空,但是部分同学通过MySQLconsole访问数据库输入密码的时候出现窗口闪退,常见的问题是原来有改过密码或者你的配置文件要求密码不...
- Mysql数据库操作指引(六)——账号密码及权限管理
-
简介:在MySQL数据库中,为了保证数据的安全性,数据管理员需要根据需要创建账户,并为每个账户赋予不同的权限,以满足不同用户的需求。...
- 一周热门
- 最近发表
- 标签列表
-
- grid 设置 (58)
- 移位运算 (48)
- not specified (45)
- patch补丁 (31)
- 导航栏 (58)
- context xml (46)
- scroll (43)
- dedecms模版 (53)
- c 视频教程下载 (33)
- listview排序 (33)
- firebug 使用 (31)
- characterencodingfilter (33)
- getmonth (34)
- hibernate教程 (31)
- label换行 (33)
- curlpost (31)
- android studio 3 0 (34)
- android应用开发 (31)
- html转js (35)
- 索引的作用 (33)
- checkedlistbox (34)
- localhost 8080 (32)
- 多态 (32)
- xmlhttp (35)
- mysql更改密码 (34)