分别使用 XHR、jQuery 和 Fetch 实现 AJAX
本文详细讲述如何使用原生 JS、jQuery 和 Fetch 来实现 AJAX。
AJAX 即 Asynchronous JavaScript and XML,异步的 JavaScript 和 XML。使用 AJAX 可以无刷新地向服务端发送请求接收服务端响应,并更新页面。
一、原生 JS 实现 AJAX
JS 实现 AJAX 主要基于浏览器提供的 XMLHttpRequest(XHR)类,所有现代浏览器(IE7+、Firefox、Chrome、Safari 以及 Opera)均内建 XMLHttpRequest 对象。
1. 获取XMLHttpRequest对象
// 获取XMLHttpRequest对象var xhr = new XMLHttpRequest();
如果需要兼容老版本的 IE (IE5, IE6) 浏览器,则可以使用 ActiveX 对象:
var xhr;if (window.XMLHttpRequest) { // Mozilla, Safari...xhr = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IEtry {xhr = new ActiveXObject('Msxml2.XMLHTTP');} catch (e) { try {xhr = new ActiveXObject('Microsoft.XMLHTTP');} catch (e) {}}
}
2. 发送一个 HTTP 请求
接下来,我们需要打开一个URL,然后发送这个请求。分别要用到 XMLHttpRequest 的 open() 方法和 send() 方法。
// GETvar xhr;if (window.XMLHttpRequest) { // Mozilla, Safari...xhr = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IEtry {xhr = new ActiveXObject('Msxml2.XMLHTTP');} catch (e) { try {xhr = new ActiveXObject('Microsoft.XMLHTTP');} catch (e) {}}
}if (xhr) {xhr.open('GET', '/api?username=admin&password=root', true);xhr.send(null);
}
// POSTvar xhr;if (window.XMLHttpRequest) { // Mozilla, Safari...xhr = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IEtry {xhr = new ActiveXObject('Msxml2.XMLHTTP');} catch (e) { try {xhr = new ActiveXObject('Microsoft.XMLHTTP');} catch (e) {}}
}if (xhr) {xhr.open('POST', '/api', true); // 设置 Content-Type 为 application/x-www-form-urlencoded// 以表单的形式传递数据xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');xhr.send('username=admin&password=root');
}
open() 方法有三个参数:
open() 的第一个参数是 HTTP 请求方式 – GET,POST,HEAD 或任何服务器所支持的您想调用的方式。按照HTTP规范,该参数要大写;否则,某些浏览器(如Firefox)可能无法处理请求。有关HTTP请求方法的详细信息可参考 https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
第二个参数是请求页面的 URL。由于同源策略(Same origin policy)该页面不能为第三方域名的页面。同时一定要保证在所有的页面中都使用准确的域名,否则调用 open() 会得到 permission denied 的错误提示。
第三个参数设置请求是否为异步模式。如果是 TRUE ,JavaScript 函数将继续执行,而不等待服务器响应。这就是 AJAX 中的 A。
如果第一个参数是 GET ,则可以直接将参数放在 url 后面,如: http://nodejh.com/api?name=admint&password=root 。
如果第一个参数是 POST ,则需要将参数写在 send() 方法里面。send() 方法的参数可以是任何想送给服务器的数据。这时数据要以字符串的形式送给服务器,如: name=admint&password=root 。或者也可以传递 JSON 格式的数据:
// 设置 Content-Type 为 application/jsonxhr.setRequestHeader('Content-Type', 'application/json');// 传递 JSON 字符串xhr.send(JSON.stringify({ username:'admin', password:'root' }));
如果不设置请求头,原生 AJAX 会默认使用 Content-Type 是 text/plain;charset=UTF-8 的方式发送数据。
关于 Content-Type 更详细的内容,将在以后的文章中解释说明。
3. 处理服务器的响应
当发送请求时,我们需要指定如何处理服务器的响应,我们需要用到 onreadystatechange 属性来检测服务器的响应状态。使用 onreadystatechange 有两种方式,一是直接 onreadystatechange 属性指定一个可调用的函数名,二是使用一个匿名函数:
// 方法一 指定可调用的函数xhr.onreadystatechange = onReadyStateChange;function onReadyStateChange() { // do something}// 方法二 使用匿名函数xhr.onreadystatechange = function(){ // do the thing};
接下来我们需要在内部利用 readyState 属性来获取当前的状态,当 readyState 的值为 4,就意味着一个完整的服务器响应已经收到了,接下来就可以处理该响应:
// readyState的取值如下// 0 (未初始化)// 1 (正在装载)// 2 (装载完毕)// 3 (交互中)// 4 (完成)if (xhr.readyState === 4) { // everything is good, the response is received} else { // still not ready}
完整代码如下:
// POSTvar xhr;if (window.XMLHttpRequest) { // Mozilla, Safari...xhr = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IEtry {xhr = new ActiveXObject('Msxml2.XMLHTTP');} catch (e) { try {xhr = new ActiveXObject('Microsoft.XMLHTTP');} catch (e) {}}
}if (xhr) {xhr.onreadystatechange = onReadyStateChange;xhr.open('POST', '/api', true); // 设置 Content-Type 为 application/x-www-form-urlencoded// 以表单的形式传递数据xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');xhr.send('username=admin&password=root');
}// onreadystatechange 方法function onReadyStateChange() { // 该函数会被调用四次console.log(xhr.readyState); if (xhr.readyState === 4) { // everything is good, the response is receivedif (xhr.status === 200) { console.log(xhr.responseText);} else { console.log('There was a problem with the request.');}} else { // still not readyconsole.log('still not ready...');}
}
当然我们可以用onload来代替onreadystatechange等于4的情况,因为onload只在状态为4的时候才被调用,代码如下:
xhr.onload = function () { // 调用onloadif (xhr.status === 200) { // status为200表示请求成功console.log('执行成功');} else { console.log('执行出错');}
}
然而需要注意的是,IE对 onload 属性的支持并不友好。除了 onload 还有以下几个属性也可以用来监测响应状态:
onloadstart
onprogress
onabort
ontimeout
onerror
onloadend
二、 jQuery 实现 AJAX
jQuery 作为一个使用人数最多的库,其 AJAX 很好的封装了原生 AJAX 的代码,在兼容性和易用性方面都做了很大的提高,让 AJAX 的调用变得非常简单。下面便是一段简单的 jQuery 的 AJAX 代码:
$.ajax({method: 'POST',url: '/api',data: { username: 'admin', password: 'root' }
}).done(function(msg) {alert( 'Data Saved: ' + msg );});
对比原生 AJAX 的实现,使用 jQuery 就异常简单了。当然我们平时用的最多的,是下面两种更简单的方式:
// GET$.get('/api', function(res) { // do something});// POSTvar data = {username: 'admin',password: 'root'};
$.post('/api', data, function(res) { // do something});
三、Fetch API
使用 jQuery 虽然可以大大简化 XMLHttpRequest 的使用,但 XMLHttpRequest 本质上但并不是一个设计优良的 API:
不符合关注分离(Separation of Concerns)的原则
配置和调用方式非常混乱
使用事件机制来跟踪状态变化
基于事件的异步模型没有现代的 Promise,generator/yield,async/await 友好
Fetch API 旨在修正上述缺陷,它提供了与 HTTP 语义相同的 JS 语法,简单来说,它引入了 fetch() 这个实用的方法来获取网络资源。
Fetch 的浏览器兼容图如下:
原生支持率并不高,幸运的是,引入下面这些 polyfill 后可以完美支持 IE8+:
由于 IE8 是 ES3,需要引入 ES5 的 polyfill: es5-shim, es5-sham
引入 Promise 的 polyfill: es6-promise
引入 fetch 探测库: fetch-detector
引入 fetch 的 polyfill: fetch-ie8
可选:如果你还使用了 jsonp,引入 fetch-jsonp
可选:开启 Babel 的 runtime 模式,现在就使用 async/await
1. 一个使用 Fetch 的例子
先看一个简单的 Fetch API 的例子 :chestnut: :
fetch('/api').then(function(response) { return response.json();
}).then(function(data) { console.log(data);
}).catch(function(error) { console.log('Oops, error: ', error);
});
使用 ES6 的箭头函数后:
fetch('/api').then(response => response.json()).then(data => console.log(data)).catch(error => console.log('Oops, error: ', error))
可以看出使用Fetch后我们的代码更加简洁和语义化,链式调用的方式也使其更加流畅和清晰。但这种基于 Promise 的写法还是有 Callback 的影子,我们还可以用 async/await 来做最终优化:
async function() { try { let response = await fetch(url); let data = response.json(); console.log(data);} catch (error) { console.log('Oops, error: ', error);}
}
使用 await 后,写代码就更跟同步代码一样。 await 后面可以跟 Promise 对象,表示等待 Promise resolve() 才会继续向下执行,如果 Promise 被 reject() 或抛出异常则会被外面的 try...catch 捕获。
Promise,generator/yield,await/async 都是现在和未来 JS 解决异步的标准做法,可以完美搭配使用。这也是使用标准 Promise 一大好处。
2. 使用 Fetch 的注意事项
Fetch 请求默认是不带 cookie,需要设置 fetch(url, {credentials: 'include'}) `
服务器返回 400,500 错误码时并不会 reject,只有网络错误这些导致请求不能完成时,fetch 才会被 reject
接下来将上面基于 XMLHttpRequest 的 AJAX 用 Fetch 改写:
var options = {method: 'POST',headers: { 'Accept': 'application/json', 'Content-Type': 'application/json'},body: JSON.stringify({ username: 'admin', password: 'root' }),credentials: 'include'};fetch('/api', options).then(response => response.json()).then(data => console.log(data)).catch(error => console.log('Oops, error: ', error))
分别使用 XHR、jQuery 和 Fetch 实现 AJAX相关推荐
- 【AJAX 笔记】AJAX 基本、HTTP 基本、原生 AJAX 的使用,jQuery / Axios / fetch 发送请求、跨域(JSONP/CORS)
文章目录 1 Ajax 概述 1.1 AJAX 简介 1.2 XML 简介 1.3 AJAX 的特点 1.3.1 AJAX 的优点 1.3.2 AJAX 的缺点 1.4 AJAX 属性和方法 2. H ...
- HTTP数据请求的方式:fetch与ajax(XMLHttpRequest)与axios
传统 Ajax 指的是 XMLHttpRequest(XHR),最早出现的发送后端请求技术,核心使用XMLHttpRequest对象,多个请求之间如果有先后关系的话,就会出现回调地狱.JQuery ...
- 有同学问我:Fetch 和 Ajax 有什么区别?
江山代有人才出,各领风骚数百年. 前言 Hello,大家好,我是编程三昧的作者隐逸王,小小前端一枚. 自昨天发了<还在死磕 Ajax?那可就 out 了!>一文后,收到了一些大家的一些评论 ...
- ajax onclick() 获取最新输入的文本框的值,如何从jQuery onclick函数的Ajax函数中获取值?...
我有一个按钮,当我点击它时,它会从我的数据库中获取数据,并根据ID将其显示在我的文本区域中.如何从jQuery onclick函数的Ajax函数中获取值? JQuery的 $('#verifyBtn' ...
- 16.JAVA之前端,HTML,CSS(选择器,盒子模型),JS,JQuery,Json,ajax
一.Web前端技术栈 1.HTML超文本标记语言 实现页面展现,形成静态网页 2.CSS层叠样式表 实现页面美化 3.JS javascript脚本语言 实现 ...
- fetch基于ajax,fetch与ajax(XMLHttpRequest)相比
前言 ES6中新增了一种HTTP数据请求的方式,就是fetch,它和XMLHttpRequest有许多相似的功能,但是相比XMLHttpRequest,fetch被设计成更具可扩展性和高效性.江湖上一 ...
- jquery ajax请求缓存,jQuery ajaxSetup() 方法及ajax缓存问题
定义和用法 ajaxSetup() 方法为将来的 AJAX 请求设置默认值. 下面的表格中列出了可能的名称/值: 名称 值/描述 async 布尔值,表示请求是否异步处理.默认是 true. befo ...
- fetch 发送 AJAX请求
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8" ...
- php ci ajax用户登录,使用jQuery和CI显示AJAX调用数据库的数据
模型似乎和控制器一样工作. AJAX将结果显示为"null",所以我认为这是因为我们需要将数据作为json发送.如何将数据放到正确的格式,并在视图中显示任何想法使用jQuery和C ...
最新文章
- typora新增主题,typora将主题导入本地
- Centos6.3修改源码遇到无法yum安装的问题
- 基于Chrome的扩展开发(二)
- java 广义表_数据结构:广义表的实现(Java)
- mysql启动失败LSB_MySQL数据库服务启动失败
- 渗透测试报告甲乙概述
- T - Memory and Trident CodeForces - 712B( 注意:* ++ = 的优先级
- 飞鸽传书官方网站方式hook一些常见的枚举文件
- 金秋10月丰收季,送3本Java书New一个秋天的对象
- iSPRINT:Google 最高能的创新加速课程,绝不允许产品走弯路!
- 教你学习CI框架codelgniter——CI框架基本配置
- [转载]AWS使用小记之EC2(Elastic Compute Cloud)
- Visio使用技巧总结
- 显卡刷bios改型号_显卡BIOS刷新方法(详细)
- ubuntu linux 12.04 下载,Ubuntu12.04下载,Ubuntu12.04更新源下载(多种下载方式)
- Paper和陈丹琦撞车是一种怎样的体验
- bzoj2555 SubString (SAM+LCT维护子树大小/ETT)
- iPhone6 iPhone6 Plus 屏幕分辨率、尺寸的问题
- python大数据读取分析_python如何读取大数据
- 基于Java的奖学金评定管理系统
热门文章
- ISP 图像传感器camera原理
- 带头尾指针的list的C实现
- js日期比较大小_node.js 内存泄漏的秘密
- python 后缀 .py .pyc .pyw .pyo .pyd的区别
- debian 9 安装后的配置,debian 9 开发环境。
- python 2 类与对象
- PHP 执行系统外部命令 system() exec() passthru()
- 韩顺平循序渐进学java 第13讲 抽象类.接口
- 无忧开通了博客园博客主页
- 委托又给我惹麻烦了————记委托链的取消注册、获取返回值