AJAX入新手入门实例讲解
本文参考或借鉴一些公开资料,特此说明。
AJAX( Asynchronous JavaScript and XML,异步的 JavaScript 和 XML),不是新的编程语言,而是一种使用现有标准的新方法。AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。
同步的概念
同步,我的理解是一种线性执行的方式,执行的流程不能跨越。一般用于流程性比较强的程序,我们做的用户登录功能也是同步处理的,必须用户通过用户名和密码验证后才能进入系统的操作。同步可以看做是一个单线程操作,只要客户端请求了,在服务器没有反馈信息之前是一个线程阻塞状态。
异步的概念
异步,是一种并行处理的方式,不必等待一个程序执行完,可以执行其它的任务。异步肯定是个多线程。在客户端请求时,可以执行其他线程,并且在把这个线程存放在他的队列里面,有序的执行。在JavaScript中实现异步的方式主要有Ajax和H5新增的Web Worker。
而ajax就可以让我们实现这里所说的异步请求。
简单地说,同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求;异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。
AJAX主要是实现页面和 web 服务器之间数据的异步传输,因此学习练习使用AJAX需要使用Web服务器。
XMLHttpRequest 工作原理
传统的web前端与后端的交互中,浏览器直接访问Tomcat的Servlet来获取数据。Servlet通过转发把数据发送给浏览器。
当我们使用AJAX之后,浏览器是先把请求发送到XMLHttpRequest异步对象之中,异步对象对请求进行封装,然后再与发送给服务器。服务器并不是以转发的方式响应,而是以流的方式把数据返回给浏览器。
XMLHttpRequest异步对象会不停监听服务器状态的变化,得到服务器返回的数据,就写到浏览器上,因为不是转发的方式,所以是无刷新就能够获取服务器端的数据。
使用js发起一个ajax请求过程,图示如下:
说明:js发起一个ajax请求过程
首先let xhr = new XMLHttpRequest();,新建一个XMLHttpRequest对象。此时xhr对象的readyState=0,表示请求未初始化。
您需要调用xhr.open(method,url,async),告诉xhr请求的方式,URL,同步or异步,让其初始化。如果执行完了这句,xhr.readyState=1,表示连接已经建立好了。
但是,如果您想发出请求,您就需要调用xhr.send()方法,如果是POST请求,您需要设置send()的参数,send(data)。调用过xhr.send()后,xhr.readyState就变成了2,请求已接收状态,或者说我们已经发出了请求。
后面的几个状态,就不需要我们通过代码去改变他了。我们的请求会通过网络,到达指定服务器,服务器响应后,再通过网络返回给我们。这个状态,我们也无法通过代码去改变。但是我们可以通过监听函数onreadystatechange去获取请求传输的进度。
当我们受到第一个字节开始,xhr.readyState=3。
在接收完全部响应数据后,请求完成,此时xhr.readyState=4。
之后处理……。
为对上面介绍有一个感性认识,下面是一个比较完整而简单的示例
包含两个文件(放在同一目录中):
一个名为demo.txt的文本文件,内容如下:
呵呵,这是来自demo.txt的内容
一个名为demo.html的网页文件,内容如下:
<!DOCTYPE html>
<html>
<head>
<meta charset=" utf-8">
<meta name="author" content="http://www.softwhy.com/" />
<title>蚂蚁部落</title>
<script>
function loadXMLDoc(){
var xmlhttp;
if (window.XMLHttpRequest){
xmlhttp=new XMLHttpRequest();
}
else{
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function(){
if(xmlhttp.readyState==4 && xmlhttp.status==200){
document.getElementById("show").innerHTML=xmlhttp.responseText;
}
}
xmlhttp.open("GET","demo.txt",true);
xmlhttp.send();
}
window.οnlοad=function(){
var obt=document.getElementById("bt");
obt.οnclick=function(){
loadXMLDoc();
}
}
</script>
</head>
<body>
<div id="show">
<h2>原来的内容</h2>
</div>
<input type="button" id="bt" value="查看效果"/>
</body>
</html>
用浏览器打开demo.html的网页文件,点击按钮读入demo.txt文本中的内容,参见下图:
创建 XMLHttpRequest 对象的语法:
variable=new XMLHttpRequest();
XMLHttpRequest对象的常见属性如下:
属性 | 描述 |
onreadystatechange | 存储函数(或函数名),每当readyState的属性改变时,就会调用该函数。 |
readyState | 存有的XMLHttpRequest的状态从0到4发生变化。 |
reponseText | 以文本形式返回响应。 |
responseXML | 以XML格式返回响应 |
status | 将状态返回为数字(例如,“Not Found”为404,“OK”为200) |
statusText | 以字符串形式返回状态(例如,“Not Found”或“OK”) |
XMLHttpRequest对象的方法
XMLHttpRequest对象的重要方法如下:
方法 | 描述 |
abort() | 取消当前请求。 |
getAllResponseHeaders() | 以字符串形式返回完整的HTTP标头集。 |
getResponseHeader( headerName ) | 返回指定HTTP标头的值。 |
void open(method,URL) | 打开指定获取或交的方法和URL的请求。 |
void open(method,URL,async) | 与上面相同,但指定异步或不。 |
void open(method,URL,async,userName,password) | 与上面相同,但指定用户名和密码。 |
void send(content) | 发送获取请求。 |
setRequestHeader( label,value) | 将标签/值对添加到要发送的HTTP标头。 |
下面给出实例
例1、利用ajax读取xml文件中的数据
本例使用了两个文件,一个是data.xml——充当服务端,一个是ajaxTest.html——充当客户端。都可以用记事本建立,注意文件名的后缀(扩展名)。放在一个文件夹中。
data.xml内容如下:
<?xml version="1.0" encoding="utf-8"?>
<root>
<data>
这是一些样本数据……它存储在XML文件中,并由JavaScript检索。
</data>
</root>
ajaxTest.html内容如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>用Ajax开发Web应用程序之示例</title>
<script type="text/javascript">
<!--
//此函数将在电击"View XML data"链接的时候执行
function ajaxRead(file){
//xmlObj,负责客户端和服务器中转
var xmlObj=null;
/*
测试不同对象的可用性
不同的浏览器执行XMLHttpRequest对象的时候不同,所以定义"xmlObj"作为XMLHttpRequest对象的时候,必须区别对待
如果没有XMLHttpRequest可用,函数以return结束来取消错误报告
*/
if(window.XMLHttpRequest){
xmlObj=new XMLHttpRequest();
}else if(window.ActiveXObject){
xmlObj=new ActiveXObject("Microsoft.XMLHTTP");
}else{
return;
}
/*
每当XMLHttpRequest状态改变时,onreadystatechange事件就触发
此事件共有5个状态,从0到4
[0]uninitialized未初始化(在XMLHttpRequest开始前)
[1]loading(一旦初始化)
[2]loaded(一旦XMLHttpRequest从服务器获得响应)
[3]interactive(当对象连接到服务器)
[4]complete(完成)
*/
/*
readyState()方法用来获得当前XMLHttpRequest的状态
状态5[编号4]是用来确认数据是否可用的,如果"是",则执行updateObj方法
此方法有2个参数:ID,填充的数据
*/
/*
xmlObj.responseXML属性是一个DOM对象,对于XML文件来说,它有点像网页中的"document"对象
通过getElementsByTagName可以获得XML文件中的任何节点
xmlObj.responseXML.getElementsByTagName('data')[0]是获得第1个名称为"data"的节点
它返回XML节点,无数据的---得到节点里的数据必须通过访问此节点的属性
firstChild.data
(firstChild获得<data>节点之间的文本节点,而"data"属性则是文本节点的实际文本)
*/
/*
xmlObj.open('GET',file,true);
xmlObj.send('');
这是ajaxRead函数中的最后一块
xmlObj的open方法打开一个通往服务器的连接(通过一个特殊的协议,这里指定为"GET"---也可以使用"POST"或其他)
请求一个文件(在这里,file变量---data.xml,是当作参数发送给了ajaxRead函数)
并且JavaScript可以操控这个请求是否为同步(false)或者异步(true,默认)
这是异步JavaScript和XML,将可以使用默认的异步方法---当使用同步之后,这个程序将不能运行
xmlObj.send('');
简单的发送了一个空字符串给服务器
如果没有这一行,xmlObj的readystate的值将不能为4,使得页面将不能更新
这个发送方法可以被用于其它东西,但是此程序仅仅从服务器得到数据,并没有发送数据给服务器,所以就到此为止
*/
xmlObj.onreadystatechange=function(){
if(xmlObj.readyState==4){
updateObj('xmlObj',xmlObj.responseXML.getElementsByTagName('data')[0].firstChild.data);
}
}
xmlObj.open('GET',file,true);
xmlObj.send('');
}
/*
此函数更新在当前页有新值的其他任何元素
第1个参数,"obj",是当前页中一个元素的id---这是被更新的对象
第2个参数,"data",指明了将要替换"obj"对象的一个新的字符串
正常地,它是一个检查并且确认当前页有含有id值为"obj"的元素的很好的方法
*/
function updateObj(obj,data){
//document.getElementById(obj).firstChild.data = data;
document.getElementById(obj).innerHTML=data;
}
//-->
</script>
</head>
<body>
<h1>用Ajax开发Web应用</h1>
<p id="xmlObj">
<a href="data.xml" title="查看XML数据" οnclick="ajaxRead('data.xml');this.style.display='none';return false">查看XML数据</a>
</p>
</body>
</html>
用浏览器打开这个页面(双击ajaxTest.html文件即可),结果如下所示:
要创建AJAX实例,需要使用服务器端,在这里使用data.xml相当于服务器端上的文件。
前面提到过,AJAX主要是实现页面和 web 服务器之间数据的异步传输,学习练习使用AJAX需要使用Web服务器,因此要想深入学习,就需要搭建Web服务器。
搭建Web服务器
Web服务器一般指网站服务器,是指驻留于因特网上某种类型计算机的程序,可以向浏览器等Web客户端提供文档,也可以放置网站文件,让全世界浏览;可以放置数据文件,让全世界下载。常见Web服务器有Apache+PHP+MySQL。在这里我们使用nodejs+express搭建web服务器。
先安装先安装nodejs,进入下面这个nodejs中文网链接 下载nodejs
选择对应的版本然后下载安装(比较简单就不多说了,如有疑惑可以百度),完了验证下nodejs安装是否成功。输入node -v命令查看版本:
测试nodejs原生的HTTP服务器
新建一个目录(也称为文件夹),例如在D:\NodeTest下新建一个myServer文件夹,在这个目录中新建(可用记事本)一个serverA.js文件(文件名你自定,只要扩展名是.js就行),写入如下代码:
var http = require("http"); //导入http模块
//开启一个监听事件,每次HTTP请求都会触发这个事件
http.createServer(function(req, res){ //req用户请求信息 res服务器响应信息
res.write('<head><meta charset="utf-8"/></head>'); //设置编码
res.write("实验测试!"); //设置响应体
res.end(); //结束事件
}).listen(3000); //设置监听端口号
// 终端打印如下信息
console.log('Server running at http://127.0.0.1:3000 or http://localhost:3000 ');
用node 命令执行
在cmd中输入 node D:\NodeTest\serverA.js
启动服务,如下所示:
打开浏览器访问 http://127.0.0.1:3000 或 http://localhost:3000,如下所示:
简单例子运行成功了,这其实是用node.js搭建了一个服务器,然后来监听端口的访问事件,最后做出相应的回应,需要指出的是,当我们关闭CMD或按CTRL+C键之后服务就关闭了。如果修改了nodejs服务器端的代码,都需要重启服务器才会生效。
在此基础上,就可以使用nodejs服务器
例、有注册和登录功能的服务器
建立一个目录D:\AJAXTest2,再在此建立一个www目录,将server.js放入AJAXTest2目录,
将user.html和ajax.js放入www目录,参见下图:
server.js内容如下:
const http = require('http');
const fs = require('fs');
const querystring = require('querystring');
const urlLib = require('url');
var users = {};
var server = http.createServer(function (req, res) {
//解析数据
var str = '';
req.on('data', function (data) {
str += data;
});
req.on('end', function () {
var obj = urlLib.parse(req.url, true);
const url = obj.pathname;
const GET = obj.query;
const POST = querystring.parse(str);
//区分——接口、文件
if (url == '/user') { //接口
switch (GET.act) {
case 'reg':
//1.检查用户名是否已经有了
if (users[GET.user]) {
res.write('{"ok": false, "msg": "此用户已存在"}');
} else {
//2.插入users
users[GET.user] = GET.pass;
res.write('{"ok": true, "msg": "注册成功"}');
}
break;
case 'login':
//1.检查用户是否存在
if (users[GET.user] == null) {
res.write('{"ok": false, "msg": "此用户不存在"}');
//2.检查用户密码
} else if (users[GET.user] != GET.pass) {
res.write('{"ok": false, "msg": "用户名或密码有误"}');
} else {
res.write('{"ok": true, "msg": "登录成功"}');
}
break;
default:
res.write('{"ok": false, "msg": "未知的act"}');
}
res.end();
} else { //文件
//读取文件
var file_name = './www' + url;
console.log(file_name);
fs.readFile(file_name, function (err, data) {
if (err) {
console.log(err)
res.write('404');
} else {
res.write(data);
}
res.end();
});
}
});
});
server.listen(8080);
//终端提示
console.log('Server running at http://localhost:8080')
ajax.js内容如下:
function json2url(json){
var arr=[];
for(var name in json){
arr.push(name+'='+json[name]);
}
return arr.join('&');
}
function ajax(json){
json=json || {};
if(!json.url)return;
json.data=json.data || {};
json.type=json.type || 'get';
var timer=null;
if(window.XMLHttpRequest){
var oAjax=new XMLHttpRequest();
}else{
var oAjax=new ActiveXObject('Microsoft.XMLHTTP');
}
switch(json.type){
case 'get':
oAjax.open('GET',json.url+'?'+json2url(json.data),true);
oAjax.send();
break;
case 'post':
oAjax.open('POST',json.url,true);
oAjax.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
oAjax.send(json2url(json.data));
break;
}
oAjax.onreadystatechange=function(){
if(oAjax.readyState==4){
clearTimeout(timer);
if(oAjax.status>=200 && oAjax.status<300 || oAjax.status==304){
json.success && json.success(oAjax.responseText);
}else{
json.error && json.error(oAjax.status);
}
}
};
}
user.html内容如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="ajax.js" charset="utf-8"></script>
<script type="text/javascript">
window.οnlοad=function (){
var oTxtUser=document.getElementById('user');
var oTxtPass=document.getElementById('pass');
var oBtnReg=document.getElementById('reg_btn');
var oBtnLogin=document.getElementById('login_btn');
oBtnLogin.οnclick=function (){
ajax({
url: '/user',
data: {act: 'login', user: oTxtUser.value, pass: oTxtPass.value},
type: 'get',
success: function (str){
var json=eval('('+str+')');
if(json.ok){
alert('登录成功');
}else{
alert('登录失败:'+json.msg);
}
},
error: function (){
alert('通信错误');
}
});
};
oBtnReg.οnclick=function (){
ajax({
url: '/user',
data: {act: 'reg', user: oTxtUser.value, pass: oTxtPass.value},
type: 'get',
success: function (str){
var json=eval('('+str+')');
if(json.ok){
alert('注册成功');
}else{
alert('注册失败:'+json.msg);
}
},
error: function (){
alert('通信错误');
}
});
};
};
</script>
</head>
<body>
用户:<input type="text" id="user"><br>
密码:<input type="password" id="pass"><br>
<input type="button" value="注册" id="reg_btn">
<input type="button" value="登录" id="login_btn">
</body>
</html>
先cd到D:\AJAXTest2目录
cd /d D:\AJAXTest2
启动 node server.js
浏览器访问localhost:8080/user.html
输入用户名和密码,开始注册或登录,试试了。
关于express
express 是nodejs的一个web框架,使用express,能够更便捷的使用nodejs.
express-generator是express应用生成器,相当于express 的骨架,进入一个web项目中后,使用express projectname命令,能快速构建projectname这个应用的目录结构。
npm install express --save -g
npm install express-generator --save -g
之后,在找到其所在位置:
现在可以使用express框架构建express项目
在cmd中使用命令:express ‘你的项目名’ -e
其中,-e 表示使用EJS模板。
例如:
express myStudy -e
安装成功后就可以使用express框架构建项目了,在当前目录中生成了一个与项目名相同目录。最后有3个选项,先不深究,意思是:
改变目录:cd expressDemo
安装依赖:npm install
运行应用程序:npm start
关于express就不进一步介绍了,感兴趣的朋友可以参考他文。
下面介绍jQueryd的Ajax方法。
jQueryd的Ajax方法
$.ajax()方法中的参数很多,我在实例中使用的只是一小部分,这里只介绍实例中所需要的参数的使用,其余更多参数还将继续学习。
$.ajax({
url:"发送请求(提交或读取数据)的地址",
dataType:"预期服务器返回数据的类型",
type:"请求方式",
async:"true/false",
data:{发送到/读取后台(服务器)的数据},
success:function(data){请求成功时执行},
error:function(){请求失败时执行}
});
说明: 这些参数均为选填,如果不设置,按默认值处理。
<1> url 默认为当前页地址
<2> dataType 可用类型:
(如果不指定,JQuery将自动根据http包mime信息返回responseXML或responseText,并作为回调函数参数传递)
xml:返回XML文档,可用JQuery处理。
html:返回纯文本HTML信息。
script:返回纯文本JavaScript代码。
json:返回json数据。
jsonp:(JSON with Padding) 是 json 的一种"使用模式",可以让网页从别的域名(网站)那获取资料,即跨域读取数据。
text:返回纯文本字符串。
说明:对于json和jsonp的区别,本小白暂时没有深入了解,目前只知道jsonp可以跨域读取数据,有待进一步学习~
<3> type 可用类型主要为post和get两种(默认为get)
get:从指定的资源请求数据(从服务器读取数据)
post:向指定的资源提交要被处理的数据(向服务器提交数据)
<4> async 异步方式,默认为true,即异步方式。当设置为false时,为同步方式。
异步方式:ajax执行后,会继续执行ajax后面的脚本,直到服务器端返回数据后,触发ajax里的success方法,这时候执行的是两个线程。
同步方式:在没有返回值之前,同步请求将锁住浏览器,用户其它操作必须等待请求完成才可以执行。
说明:这里的同步和异步有待深入理解,以下实例均使用默认的异步方式
<5> data 请求的数据,{ }中可以填入多项数据。如果不填(一般为get请求),则读取对应地址的全部数据,此时可以在console中通过console.log(res)显示数据情况。
<6> success 和 error 两个函数 一般需要设置,方便确定请求是否成功,以及请求成功后的提示或是对数据的处理和显示。
例、实现在页面上输入一个地址,点击获取经纬度,弹出该地址的经纬度。
(本例来源:https://blog.csdn.net/Yuan_mingyu/article/details/86748591 )
url=“https://restapi.amap.com/v3/geocode/geo” key:“7486e10d3ca83a934438176cf941df0c”
(此处的key值是从此地址请求数据所需的,为data数据中的一项,直接使用即可)
<!DOCTYPE html>
<html>
<head>
<meta charset=" utf-8">
<meta name="author" content="http://www.softwhy.com/" />
<title>查询经纬度</title>
<!-- js部分 -->
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>
<script type="text/javascript">
function showAdress()
{
var str = document.getElementById("text").value;
$.ajax
({
url: "https://restapi.amap.com/v3/geocode/geo",
dataType: "json",
type: "get",
data: {
address: str,
key: "7486e10d3ca83a934438176cf941df0c",
},
success:function(data){
alert(data.geocodes[0].formatted_address+"经纬度:"+data.geocodes[0].location);
console.log(data); //在console中查看数据
},
error:function(){
alert('failed!');
},
});
}
</script>
</head>
<body>
<!-- css部分 -->
<style type="text/css">
.button{
width: 100px;
height: 29px;
font-size: 16px;
color: white;
background-color: black;
padding: 0;
vertical-align: top;
border: 0;
}
.textbox{
height: 25px;
padding: 0;
vertical-align: top;
}
span{
font-size: 16px;
height: 29px;
line-height: 29px;
}
</style>
<p>利用 https://restapi.amap.com/v3/geocode/geo服务 </p>
<!-- div部分 -->
<div>
<form name="form">
<span>输入地址:</span><input id="text" class="textbox" type="text"/>
<input class="button" type="button" value="获取经纬度" οnclick="showAdress()"/>
</form>
</div>
</body>
</html>
将上述代码,保存文件名为:jQuery的Ajax实例.html。用浏览器打开这个页面(双击“jQuery的Ajax实例.html”文件即可),结果如下所示:
AJAX官网:
http://api.jquery.com/category/ajax/
AJAX教程
https://www.softwhy.com/qiduan/ajax_source/