简单理解是一种用于客户端(浏览器)与后台服务器进行异步交互(传递信息)的技术。
不需要页面全局刷新就可以进行与后台的交互。
ajax的异步请求过程:
1)浏览器通知XMLHttpRequest对象(简称XHR对象),让它去找服务器要数据用来显示给用户看
2)浏览器通知完毕后继续自己的任务
3)XHR对象接到通知后去找服务器,请求它给点数据
4)服务器经过一系列的翻找,将数据给回XHR对象
5)XHR对象拿着数据回来,并告诉浏览器已经拿到数据了
6)浏览器拿着数据去渲染显示出来
ajax的请求有同步和异步两种,下面举个通俗易懂的例子来介绍
异步请求:
假设现在处于古代战场上,连长带着一个连的人去打仗,前方战场突发了一些意外连长不知道该怎么解决,需要询问上级,连长(浏览器)就叫了一个通信兵(XHR对象),告诉它回去的线路、去找哪个上级、要带什么回来战场等信息(请求配置),将必要的信息告诉通信兵后,连长就继续去做别的任务了,通信兵带着信息回后方大本营找上级,告诉他前方发生的状况,上级经过一系列的讨论后得到解决方案(数据),上级将方案告诉给这个通信兵,让他带回前方战场,通信兵回到前方战场后将上级交代的告诉连长,连长就根据上级的指令处理这个意外。
同步请求:
同步请求与异步请求相类似,唯一不同的是,通信兵回去到带回指令的这一段时间内,连长(浏览器)什么也不做,只能干坐着等通信兵带回指令才能继续执行任务。这个期间浏览器就处于白屏等待阶段,用户不能点击页面。
XMLHttpRequest对象是浏览器的内置对象
// 1.实例化XMLHttpRequest对象
var xhr = new XMLHttpRequest();
// 设置响应返回的数据的格式(可选)
xhr.responseType = "json";
// 2.设置请求行 url是后台服务器的请求地址
xhr.open("post",url);
// 3.设置请求头
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
// 4.设置请求体
// data=“username=张三&password=123"
xhr.send(data);//data是请求的数据
// 5.监听响应
xhr.onreadystatechange = function(){
// 判断响应的状态
if(this.status === 200){
//....业务逻辑处理
var res = this.response;
}else{
// 响应失败获取不到数据的处理
}
}
方法
open(method,url,asyncFlag)
用来设置请求行,method指定请求类型get或post等,url是请求的后台服务器接口地址,asyncFlag指定是异步请求(true)还是同步请求(false),默认为true异步请求
setRequestHeader()
设置请求头,application/x-www-form-urlencoded类型是指请求发送的数据编码为“key=value”
send()
设置请求体信息,当为post请求时用该方法发送数据
属性
onreadystatechange
指定当请求状态改变时触发的方法
status
http请求返回的状态码—200表示请求成功(成功获取数据);404表示请求文件未找到(请求地址写错);500表示后台服务器出错
response
请求返回的响应信息(包括需要的数据)
jQuery有封装好的ajax方法可直接调用请求数据
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
$.ajax({
url:"",//请求地址
type:"post",//请求方式
contentType:"application/x-www-form-urlencoded",//请求数据类型
data:"",//请求数据
dataType:"",//预期服务器返回的数据类型
success:function(){
// 请求成功的回调函数,可在这里拿到响应的数据
},
error:function(){
// 请求失败的回调函数
}
})
jQuery还有两个速写方法
$.get(url[,data][,success][,dataType])
以get方式请求
url 请求地址
data 请求参数,对象
success 回调函数
dataType 响应数据类型
//===>
$.get(url,{id:2},function(data,textStatus){
console.log(data,textStatus);
})
$.post(url[,data][,success][,dataType])
以post方式请求
url 请求地址
data 请求参数,对象
success 回调函数
dataType 响应数据类型
//==>
var data = {
province:"甘肃省",
city:"兰州市",
area:"七里河",
address:"人民路",
telephone:"18891238901"
}
// content-type, querystring
$.post(url,data,function(response,status){
console.log(response,status);
})
promise对象一共有三种状态,pending、resolved(成功)、rejected(失败),一旦promise对象的状态改变了之后,就不会再改变。所以我们可以利用这一特性封装异步操作,当异步请求成功后resolve回调函数就会执行,就可以通过then方法获取异步操作的响应信息,可以通过catch方法捕获请求失败的响应信息
function get_promise(url){
//返回一个promise对象
return new Promise(function(resolve, reject){
let xhr = new XMLHttpRequest();
xhr.open("GET",url);
xhr.responseType = "json";
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
xhr.send();
xhr.onreadystatechange = function(){
if (this.readyState === 4) {
if(this.status === 200){
//请求成功后的回调
resolve(this.response);
}else{
//请求失败的回调
reject(this);
}
}
}
});
}
get_promise(url1)
.then((result)=>{
console.log("全部成功",result);
})
.catch((error)=>{
console.log("请求失败",error);
})
案例场景:查询显示每个顾客的所有地址信息(顾客基础信息在一张数据库表中,地址信息在另一张表中)
分析:要想查询显示每个顾客的所有地址信息,需要先将所有顾客信息一 一查询出来,再遍历获取顾客id再去查询这个顾客的地址信息。
要实现这一个功能就不能使用异步操作了,要使用同步操作,但是使用同步操作会使请求时间过长,用户等待浏览器加载网页的时间过长,导致用户体验效果极差。
解决办法:利用Generator函数实现异步函数的同步化
let $ = {
// 基于promise的异步操作的封装
get(url){
// 将异步操作封装到一个承诺对象中
return new Promise((resolve,reject)=>{
let xhr = new XMLHttpRequest();
xhr.open("GET",url);
xhr.responseType = "json";
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded")
xhr.send();
xhr.onreadystatechange = function(){
if(this.readyState === 4){
if(this.status === 200){
// 承诺成功
resolve(this.response)
} else {
// 承诺失败
reject(this)
}
}
}
})
}
}
// 先查询出所有的顾客信息,找到第一个顾客信息的id然后根据该id再查询该顾客的地址信息
function* bar(){
let customers = yield call($.get,"url")
console.log("所有顾客:",customers);
//有多个顾客,现在只取一个
let id = customers.data[0].id;
let address = yield call($.get,"url?id="+id)
console.log("地址信息:",id,address)
}
/*
call是异步函数的执行器{
1)在上一个请求结束后再去调用下一个请求;
2)将当前请求结果左右yield表达式的返回值返回
}
*/
function call(handler,params){
handler(params)
.then((response)=>{
// 参数作为上一个yield表达式的返回值
iterator.next(response)
})
}
let iterator = bar();
iterator.next();
Async 函数是Generator函数的语法糖,也就是对Generator函数简化和功能增强。
还是第7点的案例场景,下面使用Async 函数实现
// 基于promise的异步操作的封装
let $ = {
get(url){
return new Promise(function(resolve, reject){
let xhr = new XMLHttpRequest();
xhr.open("GET",url);
xhr.responseType = "json";
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
xhr.send();
xhr.onreadystatechange = function(){
if (this.readyState === 4) {
if(this.status === 200){
resolve(this.response);
}else{
reject(this);
}
}
}
});
}
}
async function foo(){
//await有等待的意思,可以理解为等待请求结束,并且会返回一个promise对象
let customer = await $.get("url");
console.log("customer",customer);
let id = customer.data[0].id;
let address = await $.get("url?id="+id);
console.log("address",address);
}
foo();
使用async函数修改过的代码量比使用generator函数实现的代码要少了很多。
axios是一个基于promise的ajax的框架库。
axios即可以运行在浏览器上又可以运行在nodejs上
(当你的项目使用的是vue框架的时候可以使用axios这个库完成异步请求)
<script src="https://cdn.bootcss.com/axios/0.19.0/axios.js"></script>
//示例代码
//响应拦截,请求响应回来达到浏览器前的操作
axios.interceptors.response.use(function(response){
console.log("=======interceptors===");
return response;//一定要返回,不然后面的then方法就获取不到数据进行处理
},function(error){
//当任何一个ajax请求出现异常的话都会打印错误信息!
console.log("拦截器异常")
return Promise.reject(error);
})
axios({
url:"",//请求地址
method:"post",//请求类型
data:{//请求数据
realname:"张三test",
telephone:"1827723309"
},
headers:{//请求头
"Content-Type":"application/x-www-form-urlencoded"
},
//请求发送前对请求数据的操作
transformRequest:[(data,headers)=>{
// 请求发送前将data转换为查询字符串
let q = "";
for(let key in data){
let val = data[key];
q+=key+"="+val+"&"
}
//截取掉最后一个多余的&符号
return q.slice(0,q.length-1);
}]
})
.then((response)=>{
console.log(response);
})
.catch((error)=>{
console.log("异常信息",error);
})
axios使用方法(部分)
axios(config)
返回值:返回一个ajax承诺对象
参数:
config 是配置对象
{
url,地址
method,请求方法
data, 请求体参数(post请求)
params , 请求行参数(get请求)
headers:{请求头
“Content-Type”:“application/json”
},
responseType:“json”,响应数据累得
withCredentials:false, 默认不携带cookie
baseURL, // 基础路径
timeout, // 5000 请求超时的最大时间
transformRequest:[(data,headers)=>{},()=>{}]
在请求发送到服务器端之前允许我们对data进行处理,一般用于编码
transformResponse:[(data)=>{}]
在响应结果达到then/catch之前对结果进行处理,data为后端返回来的原始数据
paramsSerializer: function (params) {
return Qs.stringify(params, {arrayFormat: ‘brackets’})
},
序列化params为查询字符串。get方式传递的参数需要拼接在浏览器地址栏的url的后面,只能为查询字符串
此文章为作者本人原创,仅限于作者本人的学习总结记录,若有错误之处请留言提出。