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工作流程

Javascript(笔记49) - AJAX - AJAX简介、工作流程、同步、异步_javascipt

用户界面,由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

> node nodeServer.js

按下“发送同步请求”按钮时,等待5秒,弹出: hello ajax!!!

Javascript(笔记49) - AJAX - AJAX简介、工作流程、同步、异步_javascipt_02

在按下同步请求时,浏览器处于阻塞状态,这时的用户名表单是不能交互的;

同时获取数据的那段代码也在等待执行:直到响应完成,也就是5秒后,接收到 data 后,才可以交互;

// 获取响应的数据
var data = xhr.responseText;

Javascript(笔记49) - AJAX - AJAX简介、工作流程、同步、异步_ajax_03

看下网络标头:请求方法是GET;

Javascript(笔记49) - AJAX - AJAX简介、工作流程、同步、异步_javascipt_04

看下响应时长:服务器响应时长5秒;

Javascript(笔记49) - AJAX - AJAX简介、工作流程、同步、异步_javascipt_05


异步请求:在服务端响应之前浏览器可以执行其他操作,无需要等待服务器响应

异步请求示例

异步请求无需等待服务器响应,仍然可以继续执行代码和操作页面;

只需在 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 这个状态呢,因为初始化之后才监听;)

Javascript(笔记49) - AJAX - AJAX简介、工作流程、同步、异步_ajax_06

也就是说,我们等 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>

Javascript(笔记49) - AJAX - AJAX简介、工作流程、同步、异步_javascipt_07

点击“异步请求”按钮后,还可以与 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 环境里启用

> node nodeServe.js

返回 false 的效果:

Javascript(笔记49) - AJAX - AJAX简介、工作流程、同步、异步_ajax_08

返回 true 的效果:

Javascript(笔记49) - AJAX - AJAX简介、工作流程、同步、异步_ajax_09

查看标头:

Javascript(笔记49) - AJAX - AJAX简介、工作流程、同步、异步_javascipt_10


检验用户名(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>