AJAX 是什么
Ajax(Asynchronous JavaScript and XML) 异步JavaScript和XML;sync 同步的;async 异步的;
客户端与服务器,可以在 不必刷新整个页面 的情况下,与服务器进行异步通讯的技术;
AJAX:只新刷局部页面的技术;
1)Javascript : Ajax技术主要开发语言;
2)HTML/XML/JSON:用于封装请求数据和响应数据;
3)DOM:通过 DOM 修改页面元素,实现页面局部刷新;
4)CSS:改变样式,美化页面效果,提升用户体验;
5)Ajax引擎(核心):即 XMLHttpRequest 对象,以异步方式在客户端和服务器之间传递数据;
为什么用AJAX
不刷新整个页面,只刷新局部
1)更新部分页面,有效利用带宽
例如,只是登录,就没必须刷新整个页面;通常表单提交是同步的,提交过程中,页面是不能交互的;
2)提供连续的用户体验
例如,看视频时,点赞和评论等交互行为,不影响视频的正常播放;
3)关键词自动补全或地图加载
例如,搜索框搜索时,关键词在下框自动补全;地图加载时,只显示正在看的区域等;
AJAX工作流程
用户界面,由JS获得用户数据,由AJAX引擎(主要是 XMLHttpRequest对象)发送给服务器;服务器将处理完的局部数据(非整个页面)封装成XML/JSON/HTML的格式返回给引擎,再用DOM和CSS修改和修饰页面渲染给用户;
传统Web与Ajax差异
| 传统Web | Ajax技术 |
发送请求方式 | 提交表单方式发送请求 | 异步引擎对象发送请求 |
服务器响应 | 响应内容是完整页面 | 响应内容只是需要的数据 |
客户端处理方式 | 需要等待服务器响应完成并重新加载整个页面后用户才能进行操作 | 可以动态更新页面中的部分内容,用户不需要等待请求的响应 |
同步的理解:空中加油时,俩飞机需保持相同速度和位置;排队做核酸,前面没做完,后面就要等待;
异步的理解:银行取号,取完号后坐一边休息,可以干点别的等待叫号;
XMLHttpRequest
Javascript对象 XMLHttpRequest是整个Ajax技术的核心,提供了异步发送请求的能力;
常用方法
方法 | 描述 |
open(method,URL,async) | 建立与服务器的连接 method: 请求方式,“GET”(默认) 或 “POST”,需大写 URL:请求地址 async:是否使用异步请求,true(默认) 或 false |
send(content) | 发送请求 content: 请求参数,只有POST请求才能通过 send() 发送参数 |
setRquestHeader(header,value) | 设置请求头信息,在用 post 请求方式时使用 header: 要设置的头部的名称 value: 要设置的头部的值
xhr.open("POST","SimpleServlet",true); xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded;charset=utf-8"); xhr.send("name=tom&age=22"); |
getAllResponseHeaders | 以字符串形式返回完整的 http 标头集 |
常用属性
属性 | 描述 |
onreadystatechange | 事件属性,指定回调函数,当 readyState 属性改变时触发执行 |
readyState | 存有的XMLHttpRequest的状态从0到4发生变化。 0:请求未初始化 1:服务器连接已建立 2:请求已接收 3:请求处理中 4:请求已完成,且响应已就绪 |
responseText | 以文本形式返回响应 |
responseXML | 以XML形式返回响应 |
status | 表示HTTP请求响应的状态 200 服务器响应正常 400 无法找到请求资源 403 没有权限访问 404 访问的资源不存在 500 服务器内部错误 |
status | 以字符串形式返回状态(如:Not Found 404 或 ok 200) |
XMLHttpRequest 即支持发送开步请求,又支持同步请求:
同步请求:在服务端响应之前,浏览器处于阻塞状态,等待服务端响应,此时不能进行页面交互操作;
同步请求示例
通过本示例显示同步请求中,浏览器处于阻塞状态;
阻塞状态时,页面不能交互,从而影响用户体验;
ajax.html
<input type="button" value="发送同步请求" onclick="sendSync()"> // 按钮
<script>
function sendSync(){
// 1. 创建XMLHttpRequest对象
var xhr = new XMLHttpRequest();
// 2. 初始化连接 一般是3个参数; 以 get 方式,与URL服务器,建立同步连接,同步请求取 false
xhr.open("GET","http://localhost:9527",false);
// 3. 发送请求, 没有数据就写 null , get 的方法必须写 null
xhr.send(null);
// 4. 获取响应的数据
var data = xhr.responseText;
alert(data);
}
</script>
用node.js写个 http 响应请求的服务;
var http = require('http');
http.createServer(function (request, response) {
response.setHeader('Access-Control-Allow-Origin', '*');
console.log('有人访问了');
const start = new Date();
while (new Date() - start < 5000) {} // 人为的暴力加入延时5秒;
response.write('hello Ajax!!!'); // 延时5秒后执行
response.end();
}).listen(9527);
在终端,把这个服务启动:需要先安装node
按下“发送同步请求”按钮时,等待5秒,弹出: hello ajax!!!
在按下同步请求时,浏览器处于阻塞状态,这时的用户名表单是不能交互的;
同时获取数据的那段代码也在等待执行:直到响应完成,也就是5秒后,接收到 data 后,才可以交互;
// 获取响应的数据
var data = xhr.responseText;
看下网络标头:请求方法是GET;
看下响应时长:服务器响应时长5秒;
异步请求:在服务端响应之前浏览器可以执行其他操作,无需要等待服务器响应
异步请求示例
异步请求无需等待服务器响应,仍然可以继续执行代码和操作页面;
只需在 xhr.open() 方法中,把参数改为 true 就可以了;
<input type="button" value="发送异步请求" onclick="sendAsync()"> // 按钮
<script>
function sendAsync() {
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://localhost:9527", true); // 建立异步请求
xhr.send(null);
var data = xhr.responseText;
alert(data);
}
</script>
但这样会出现个新问题:既然无需要等待服务器响应,那么服务器还没响应完呢,代码就执行完了;
var data = xhr.responseText;
导致这一句先被执行了,data 并没有获取到数据,alert 弹窗就是空的;
这时候就要用 XMLHttpRequest 对象的状态属性了,通过事件来监听请求的状态和响应的状态,当确定各状态就绪后,再接收数据;
先看 onreadystatechange 这个事件属性:指定回调函数,当 readyState 属性改变时触发执行
<input type="button" value="发送异步请求" onclick="sendAsync()">
<script>
function sendAsync() {
var xhr = new XMLHttpRequest();
// 当状态发生改变时执行
xhr.onreadystatechange = function(){
// 既然是监听readyState状态的,就输出看看
console.log("xhr.readyState: " + xhr.readyState);
console.log("xhr.status :" + xhr.status);
}
xhr.open("GET", "http://localhost:9527", true);
xhr.send(null);
}
</script>
这里的服务器,还使用上例中延时5秒的node服务器环境;
在控制台,可以看到 readyState 的4个状态码和 status 的4个响应码;说明 onreadystatechange 事件属性,监听到了 readyState 的4次变化,即从1-4; status 也从0 变为200;而状态码 4 和 响应码 200 正是我们等待就绪的信号;(为啥 readyState 没有 0 这个状态呢,因为初始化之后才监听;)
也就是说,我们等 readyState 状态码为 4 (就绪)时, status 响应码为 200 (正常),才可以获取数据,否则我们不确定服务器的响应是否正常,会给我们传来什么样数据;
这就像AB两人约吃饭,A发出请求B去吃饭,得先确定B收到了请求,还得等B回应同意来吃一样;
判断的顺序还不能变:即判断 readyState 在先,判断 status 在后;
如果响应码是404,这是我们常见的未找到页面;响应码是500时,也是开发常见的服务器内部错误;
<input type="button" value="发送异步请求" onclick="sendAsync()">
<script>
function sendAsync() {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
// 判断请求状态码就绪 ,同时判断响应状态码完成,才可以获取数据
if (xhr.readyState == 4 && xhr.status == 200) {
var data = xhr.responseText;
alert(data);
}
}
xhr.open("GET", "http://localhost:9527", true);
xhr.send(null);
}
</script>
点击“异步请求”按钮后,还可以与 input 交互,5秒后,弹出信息: hello ajax!!!
注意:监听事件要放在 send()方法前面;
IE7以下的版本,没有 XMLHttpRequest 对象,所以封装一个兼容函数
封装兼容函数
// 封装兼容函数
function createXHR(){
if(window.XMLHttpRequest){
return new XMLHttpRequest();
}else{ // 兼容IE老版本
return new ActiveXObject('Microsoft.XMLHTTP');
}
}
那么之前的 new 一个对象,就可以改用兼容的写法;
// var xhr = new XMLHttpRequest();
var xhr = createXHR();
应用场景
使用AJAX无刷新校验用户名是否已经被使用,比用提交表单的方式体验好很多;
检验用户名(GET方式)
需求:当用户名文本框失去焦点时,发送请求到服务器,判断用户名是否存在;
如果已经存在,则提示:该用户名已经被使用;
如果不存在,则提示:该用户名可以使用;
使用GET方式发送请求:
1)通过 queryString 形式发送请求参数,即附加在 url 后面;
2)不能使用 send() 方法发送请求参数,该方法参数设置为 null ;
ajax.html 前端页面
<form action="">
用户名:<input type="text" id="username" onblur=checkExists(this.value) />
<span id="info"></span>
</form>
<script>
var info = document.querySelector('#info');
var user = document.querySelector('#username');
// 校验用户名
function checkExists(username) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
var data = xhr.responseText;
console.log(data);
if (data == "true") {
info.innerHTML = "用户名可以使用";
} else {
info.innerHTML = "用户名已经被占用";
user.select();
}
}
}
xhr.open("GET", "http://localhost:9527?username=" + username, true);
xhr.send(null);
}
</script>
使用“GET”方式提交请求,用户名传参写在 URL 的后面;不能写在 send() 方法里,参数必须是 null;
nodeServe.js 后端响应页面
主要作用是接受前端的用户名,判断是否被占用,然后返回 true 和 false;
var http = require('http');
http.createServer(function (request, response) {
response.setHeader('Access-Control-Allow-Origin', '*');
console.log('有人访问了');
var url = request.url.substring(2);
var username = url.split('=')[1];
if(username == "admin" || username == "jack"){
response.write("false");
}else{
response.write("true");
}
response.end();
}).listen(9527);
node 环境里启用
返回 false 的效果:
返回 true 的效果:
查看标头:
检验用户名(POST方式)
POST方法请求接收不到 xhr.responseText ,我也不知道为什么;
使用POST方式发送请求:
1)要设置请求头 application/x-www-form-urlencoded ;
2)使用 send() 方法发送请求参数 ;
<form action="">
用户名:<input type="text" id="username" onblur=checkExists(this.value) />
<span id="info"></span>
</form>
<script>
var info = document.querySelector('#info');
var user = document.querySelector('#username');
// 校验用户名
function checkExists_post(username) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
var data = xhr.responseText;
console.log("xhr.responseText:",data);
if (data == "true") {
info.innerHTML = "用户名可以使用";
} else {
info.innerHTML = "用户名已经被占用";
user.select();
}
}
}
xhr.open("POST", "http://localhost:9527", true);
xhr.setRequestHeader('Content-Type',"application/x-www-form-urlencoded;charset=utf-8");
xhr.send("username=" + username);
}
</script>