AJAX 概述
AJAX是多种技术的综合产物,不能简单称为一种技术。
异步与同步
异步和同步是两种不同的编程模式。
同步:指程序按照预定的顺序依次执行,即每个任务必须在前一个任务完成后才能开始执行。
在同步编程中,如果一个任务阻塞了,那么整个程序就会被阻塞。同步任务通常被称为“阻塞式任务”,因为它们阻塞了应用程序的执行。同步编程模型适用于一些简单的应用场景,但是会导致程序执行时间过长,资源占用效率低下
异步:指程序在执行过程中不必按照顺序执行,任务可以在完成之前或之后执行。
异步编程通常会利用异步 I/O,事件和回调等机制来实现。异步任务通常被称为“非阻塞式任务”,因为它们不会阻塞应用程序的执行。异步编程用于那些需要并发处理多个任务的大型应用程序,可以提高程序执行效率。但是异步编程也会增加程序的复杂度,需要使用一些特殊的编程技术和工具。
线程、AJAX都支持异步和同步,如多线程并发就是异步,AJAX请求通常也是异步的。
AJAX原理
AJAX请求由前端发起,属于前端的技术范畴,与后端相独立。
AJAX使用JavaScript的内置对象XMLHttpRequest来完成请求的发送,AJAX请求的响应内容可以是XML、JSON、纯文本等。
后端发送完对AJAX请求的响应后,可以调用发送请求的XMLHttpRequest对象的相关属性(如responseText)来获取后端发送的响应内容,并使用JS在特定的区域(标签对)内做出局部更新,从而避免了传统请求刷新整个网页的低效率,并提高用户体验。
传统请求及缺点
传统请求区分于AJAX请求,当一次传统请求发出后,浏览器会刷新整个网页,而再将后端响应的内容进行渲染,传统请求对用户是显式的,用户的操作是间断的、不连贯的(有等待响应的空窗期,此时页面是空白的)。AJAX请求(无论是同步的还是异步的)则是“页面内的请求”,可以做到只对页面的局部进行刷新(使用JS),整个AJAX请求对于用户是隐式的,用户的操作是流畅的、连贯的(局部渲染发生在页面内)。
发送传统请求的方式:
地址栏URL+回车
点击超链接
form表单的提交
JS代码:
window.open(url) document.location.href = url window.location.href = url ...
AJAX同步请求
AJAX同步请求有别于传统请求的同步,AJAX同步请求,指该AJAX请求得到响应之前,不能发送下一个AJAX请求(不论该请求是同步还是异步),必须等该AJAX请求响应结束,才会发送下一个请求。

使用同步请求,会阻塞当前线程。
function query(){
let api = {}
console.log("querying...");
$.ajax({
type : "GET"
,url : "https://yesno.wtf/api"
,data : "_="+ new Date().getTime()
,async : false
,success : function(json){ // 同步请求时线程被阻塞,必须等待此函数回调执行完毕才可继续
api = json
}
})
return api; // 异步请求时,这里会先返回{};同步请求时,需要等请求响应完毕后才能继续执行
}使用同步请求的情况:一个AJAX请求为响应结束时,不能发送下一个AJAX请求,必须排队、必须等待完成时。如:用户注册的校验
- 用户名需要发送ajax请求进行校验
- 邮箱地址也需要发送ajax请求校验
- 其他的也可能需要发送ajax请求。。。
- 并且最终注册按钮的时候,也是发送ajax请求进行注册。
- 显然,注册的Ajax请求和校验的ajax请求不能异步,必须等待所有的校验ajax请求结束之后,注册的ajax请求才能发。
AJAX异步请求

大部分情况下,都是使用AJAX异步请求。
AJAX请求的发送
AJAX请求支持同步方式和异步方式。使用JavaScript编写,使用内置的XMLHttpRequest对象完成请求的发送与响应内容的接受。
请求的发送分为四步:
- 创建AJAX核心对象
- 注册回调函数
- 开启通道
- 发送请求
XMLHttpRequest详解
现代浏览器都支持XMLHttpRequest内置对象,直接使用(new)即可。
// 创建XMLHttpRequest对象
var xhr = new XMLHttpRequest();XMLHttpReques的实例方法(通过对象调用):
// 取消当前请求
.abort()
// 返回响应头部信息
.getAllResponseHeaders()
// 返回特定的响应头部信息
.getResponseHeader()
// 建立连接
.open(method, url, async, user, psw)
/*
* method: 请求类型,"GET" "POST"
* url: 访问资源路径
* async: true|false,是否异步,true表示使用异步请求,false表示使用同步请求
* user、psw: 可选。访问资源时需要的口令
*/
// 将请求发送到服务器,使用GET方式
.send()
// 将请求发送到服务器,使用POST方式
.send(str) // str: 请求体
// 添加请求头(标签/值对)
.setRequestHeader()XMLHttpReques的对象属性:
.onreadystatechange // 定义当 readyState 属性发生变化时的回调函数
.readyState // 保存对象的状态
/*
* 0:请求未初始化
* 1:服务器连接已建立
* 2:请求已收到
* 3:正在处理请求
* 4:请求已完成且响应已就绪
*/
.responseText // 以字符串返回响应数据(不管服务器响应回来的是什么(普通文本、XML、JSON、HTML...),都以普通文本的形势获取。)
.responseXML // 以XML数据返回响应数据(自动封装为document对象)
.status // 响应的状态码
.statusText // 响应的状态描述信息(响应头中的)AJAX发送GET请求实例
前端示例:
//1. 创建AJAX核心对象
var xhr = new XMLHttpRequest();
//2. 注册回调函数
xhr.onreadystatechange = function(){
if (this.readyState == 4) {
if (this.status == 200) {
// 使用innerHTML属性渲染返回的html内容
document.getElementById("mydiv").innerHTML = this.responseText
}else{
alert(this.status)
}
}
}
//3. 开启通道
xhr.open("GET", "/ajax/ajaxrequest2", true)
//4. 发送请求
xhr.send()
// 可以通过给页面元素注册回调函数来实现发送,如:
<script type="text/javascript">
window.onload = function () {
document.getElementById("btn").onclick = function () {
...
}
</script>后端设置的响应内容类型:
response.setContentType("text/html;charset=UTF-8");
// 响应内容类型为html,使前端接受到数据后可以通过innerHTML属性进行渲染GET请求提交数据:HTTP协议规定,在“请求行”(URL?name=value...)上提交,以键值对的形式。
GET请求的缓存问题
在HTTP协议中,GET请求会先被浏览器缓存起来,如果出现URL完全一样(包括提交参数)的GET请求,会先查找缓存,缓存中没有才会发送请求。POST请求不会被缓存(无意义)。
AJAX缓存问题,就是浏览器在发送AJAX的GET请求时,走了缓存,导致接受不到服务器给的响应内容。对于低版本的IE浏览器来说,容易出现这个问题,现代的大部分浏览器都不存在AJAX缓存的问题了。
GET请求缓存可以直接从浏览器缓存中获取资源,不需要从服务器上重新加载资源,速度较快,用户体验好,但缺点是无法实时获取最新的服务器资源。
解决GET请求缓存问题:在URL末尾添加动态的参数,使每次请求都不是完全一样的,这样就不会走浏览器的缓存了。比如:
- 添加时间戳:
"url?t=" + new Date().getTime() - 添加随机数:
"url?t=" + Math.random()
AJAX发送POST请求实例
// 发送POST请求时,需要添加请求头,模拟表单方式,这样后端才可以解析
...
// 4. 发送AJAX POST请求
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded") // 设置请求头的内容类型。模拟form表单提交数据。
// 获取表单中的数据
var username = document.getElementById("username").value;
var password = document.getElementById("password").value;
// send函数中的参数就是发送的数据,这个数据在“请求体”当中发送。
xhr.send("username="+username+"&password="+password)
// 请求头的第二个参数"application/x-www-form-urlencoded"可以通过form表单的属性获得(IDE提示)
<form enctype="application/x-www-form-urlencoded"></form>后端设置的响应内容类型:
response.setContentType("text/html;charset=UTF-8");
// 响应内容类型为html,使前端接受到数据后可以通过innerHTML属性进行渲染AJAX乱码问题
乱码本质是一样的,后端设置请求体的编码、相应内容的编码即可解决。
// 设置请求体的编码
request.setCharacterEncoding("UTF-8");
// 设置相响应内容的编码
response.setContentType("text/html;charset=UTF-8");Tomcat10+后不会出现中文乱码(不论是请求体还是响应体)。
详细见:JavaWeb/字符集。
