一、ajax的准备
程序中的同步:不同时操作,即没有一起执行,一条一条从上往下依次执行
alert("1");
alert("2");
alert("3");
alert("4");
程序中的异步:同时操作,即一起执行的代码,不受上面代码的影响
js中有特定的场景才会产生异步程序,例如事件和计时器,其大概过程是:代码从上向下依次执行,绑定的事件和计时器本身执行了,但是绑定事件的处理函数和计时器内部的回调函数是在等待状态,它在等待事件或延迟的时间,等待的状态其实也是在执行中,然后代码继续向下一行执行,在某一瞬间绑定事件的处理函数和计时器内部的回调函数与下一行代码同时执行了,这二者就叫异步。
// 1.事件中存在异步
// JS中有特定的场景才会产生异步程序
var a = 10;
// 绑定事件的过程执行了,但只是执行了绑定,绑定的事件处理函数没有被执行
document.onclick = function(){
a = 20;
}
console.log(a);
// 2.计时器中存在异步
var b = 10;
// 每隔指定的时间,执行一次回调函数
// 计时器自身是同步执行了的,只是内部的回调函数,没有立即执行,在等待
// 内部的回调函数与外部代码之间是异步:会有一瞬间在进程中同时存在
setTimeout(() => {
a = 20;
}, 100);
console.log(a);
// 异步会导致一些问题的发生:
// 异步其实就表示将来
// 当前如何获取将来?不能获取!
// 只能在将来获取将来
// var a = 10;
// setTimeout(() => {
// a = 20;
// console.log(a);
// }, 100);
// 预置函数:提前做好将来的准备,预置函数并没有立即执行,必须在将来执行,因为只有到将来,才知道执行哪个预置函数
二、ajax请求的过程中产生了哪些信息
详情见浏览器控制台中的network,点击对应的请求地址,可以打开详细信息:概要;接收头信息;发送头信息;发送的数据。
学习ajax需要对ajax和http的状态码有一点的了解。
三、ajax的介绍
ajax的运行环境是在服务器下运行,它是前后端交互的重要手段。
ajax是一些技术的组合体:
- a:异步
- j:js
- a:and
- x:数据
一些技术的组合体:
- 异步的js:事件
- 其他的js:数据的解析
- xhr对象:连接前后端的载体,XHLHttpRequest
- 服务端的数据:txt,php,json,xml,html…
异步请求数据的优点
- 同时执行,效率高,当前请求不会影响其他程序
- 可以在不中断浏览器其他任务的情况下,加载新数据
- 无刷新,加载数据
- 提高用户体验
- 减轻服务端和带宽的负担
异步请求数据的缺点
- 破坏了浏览器自身的前进后退功能
- 因为新数据是将来才有可能拿到,那么会让搜索引擎的爬虫忽略新数据中的关键字
- 浪费性能
四、ajax的实现
1.固定语法,这里利用打电话来生动形象的描述ajax的实现
// 打电话:
// 1.造手机:创建xhr对象
var xhr = new XMLHttpRequest();
// 2.准备拨号:拨号键盘,选择打电话的方式(免提或听筒),对方的号码
// xhr对象身上的拨号键盘
// 选择听筒还是免提:post和get
// 对方的号码:要请求的地址
xhr.open("get","要请求的地址");
// 3.假设通了,要说话(歪),说话是不是发送数据
// xhr对象身上的send
xhr.send("");
// 4.通了么?观察状态(手机好用不;对方手机状态(关机,没话费,没信号,挂了))
// 观察状态:事件
xhr.onreadystatechange = function(){
// 什么状态是成功:
// 手机没问题:设备的状态,载体的状态:通了:4
// 对方手机状态(运营商):运营商的状态:通了:200
if(xhr.readyState == 4 && xhr.status == 200){
// 如果成功了,还得通过手机接听到信息:还是需要找xhr对象拿数据
console.log(xhr.responseText);
}
2.发送数据的方式
// 注意文件夹的位置
// 相对路径:相对于当前文件
var url = "data/hello.txt";
// hello.txt内可写任意内容
// 服务器绝对路径:从根路径开始找:能在浏览器中直接打开的地址
// var url = "http://localhost/ajax/data/hello.txt";
// 路径======地址
// get方式
document.onclick = function(){
var xhr = new XMLHttpRequest();
xhr.open("get",url);
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
console.log(xhr.responseText);
}
}
}
// post方式
document.onclick = function(){
var xhr = new XMLHttpRequest();
xhr.open("POST",url);
// 设置发送头信息,发送数据的格式,为表单数据格式,固定格式
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.send(data);
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
cb(xhr.responseText);
}
}
}
3.将其分别封装成函数
// 记事本文件中,所有内容都是数据
// ajaxGet("http://localhost/ajax/data/hello.txt");
// json文件中,所有内容都是数据
// ajaxGet("http://localhost/ajax/data/data.json");
// php文件中,只有被返回的内容才是数据
// ajaxGet("http://localhost/ajax/data/data.php");
// get函数的封装
// document.onclick = function(){
// var dizhi = "http://localhost/ajax/data/data.php?abc=123&qwe=456&asd=hello";
// ajaxGet(dizhi,function(res){
// console.log(res);
// });
// }
// 注意:使用回调函数,拿到ajax的成功后的数据
function ajaxGet(url,cb){
var xhr = new XMLHttpRequest();
xhr.open("GET",url);
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
// 只有在此处才能拿到数据,因为此处是事件处理函数,又不能使用return返回数据
// 所以,解决方案是:利用回调函数
// xhr.responseText;
cb(xhr.responseText);
}
}
}
// 异步已经出现了,ajax内部有事件
// 其实除了事件,ajax自身的执行过程也是异步
// ajax:
// 等着,我去请求个数据
// 什么时候成功?
// 不知道,等我结束了,就成功了
// 注意:
// 不是有回调函数就是异步
// 是异步的问题,可以使用回调函数解决
// return跟着函数走
// post函数的封装
document.onclick = function(){
var dizhi = "http://localhost/ajax/data/data.php";
ajaxPost(dizhi,function(res){
console.log(res);
},"abc=987&zxc=hello");
}
function ajaxPost(url,cb,data){
var xhr = new XMLHttpRequest();
xhr.open("POST",url);
// 设置发送头信息,中,发送数据的格式,为,表单数据格式
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.send(data);
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
cb(xhr.responseText);
}
}
}
// 接收数据的方法
// 接收get数据
// $a = $_GET["abc"];
// $b = $_GET["qwe"];
// $c = $_GET["asd"];
// echo "hello这是接收到的数据,稍作处理,再还给你:".$a."-----".$b."-----".$c;
// 接收post数据
// $q = $_POST["abc"];
// $w = $_POST["zxc"];
// 后台要处理
// echo "hello这是接收到的数据,稍作处理,再还给你:".$q."-----".$w;
// 既能接收get数据,又能接收post数据
$u = $_REQUEST["user"];
$p = $_REQUEST["pass"];
echo "后台接收到的数据:".$u."---".$p;
4.接着尝试把两种方式封装成一个函数
document.onclick = function(){
var url = "http://localhost/ajax/data/get-post.php";
ajax({
success:function(res){
console.log(res);
},
url:url,
type:"get", // 这里根据需求传入get或post
data:"user=admin&pass=123"
});
}
function ajax(ops){
// 先处理默认属性
ops.type = ops.type || "get";
ops.data = ops.data || "";
// 根据当前的请求方式,决定是否需要拼接数据,处理url
ops.url = ops.type=="get" ? ops.url + "?" + ops.data : ops.url;
// if(ops.type=="get"){
// ops.url = ops.url+ops.data
// }
// 创建xhr对象
var xhr = new XMLHttpRequest();
// 开启请求
xhr.open(ops.type, ops.url);
// 根据类型决定send的内容及内容数据格式
if(ops.type == "get"){
xhr.send();
}else{
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.send(ops.data);
}
// 开启监听
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
// 执行回调函数,取出数据
ops.success(xhr.responseText);
}
}
}
5.发送数据:
- get:将数据放在url后,进行拼接即可
- post:将数据放在send的参数内,但是提前要设置发送数据的格式:ajax对象.setRequestHeader(“Content-type”,“application/x-www-form-urlencoded”);
五、ajax中的一些小问题
1.兼容问题:xhr对象的兼容和事件的兼容,二者都几乎可以不考虑
- xhr对象的兼容,大部分浏览器都支持new XMLHttpRequest()方法,IE5以下的支持new ActiveXObject(“Microsoft.XMLHTTP”)方法;
- 事件的兼容,大部分浏览器以下两种方式都支持:
xhr.onreadystatechange = function(){
手动判断ajax的状态和http的状态
}
xhr.onload = function(){
只需要判断http的状态
}
let xhr;
if(XMLHttpRequest){
xhr = new XMLHttpRequest();
}else{
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
// console.log(xhr);
xhr.open("get","data/hello12313.txt");
xhr.send();
xhr.onreadystatechange = function(){
// 手动判断ajax的状态和http的状态
if(xhr.readyState === 4 && xhr.status === 200){
console.log(xhr.responseText);
}else if(xhr.readyState === 4 && xhr.status !== 200){
console.log(xhr.status);
}
}
// xhr.onload = function(){
// // ajax的状态默认为4
// if(xhr.status === 200){
// console.log(xhr.responseText);
// }
// if(xhr.status !== 200){
// console.log(xhr.status);
// }
// }
2.缓存问题:当get请求时,浏览器会默认缓存要请求的资源,浏览器默认缓存信息,提升用户体验。
浏览器第一次打开某个网页时,会自动下载当前网页上的一些资源,浏览器第二次打开同一个地址时,会自动先从自身缓存中查找资源,如果有,直接加载,如果没有,再从服务器重新请求。
如果缓存中有了,就不在去服务器中请求了,如果这时,服务器中的数据正好改了,有可能会拿不到新数据。
为什么会缓存?因为浏览器认为这是同一个地址。
最终解决方案:在get请求的url后拼接时间戳:let url = “data/hello.txt?__vst=” + new Date().getTime();
只有get有缓存问题,post没有该问题
document.onclick = function(){
let xhr = new XMLHttpRequest();
let url = "data/hello.txt?__qft=" + new Date().getTime();
xhr.open("get",url);
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
console.log(xhr.responseText);
}else if(xhr.readyState === 4 && xhr.status !== 200){
console.log(xhr.status);
}
}
}
可将时间戳写到之前封装的函数中,代码如下:
function ajax(ops){
ops.type = ops.type || "get";
ops.data = ops.data || "";
// ops.url = ops.type=="get" ? ops.url + "?" + ops.data : ops.url;
if(ops.type=="get"){
// 在get请求时,使用时间戳避免,缓存问题
let t = new Date().getTime();
ops.url = ops.url + "?__qft="+ t + "&" + ops.data;
}
var xhr = new XMLHttpRequest();
xhr.open(ops.type, ops.url);
if(ops.type == "get"){
xhr.send();
}else{
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.send(ops.data);
}
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
ops.success(xhr.responseText);
}
}
}
3.异步同步,ajax自身默认异步执行,但也可以强行修改成同步执行
解决方法是:在open方法中传入第三个参数,布尔值,true为异步,默认值,false为同步,官方不推荐使用,不要使用
let xhr = new XMLHttpRequest();
// true为异步(默认),false为同步
xhr.open("get","data/hello.txt",false);
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
console.log(xhr.responseText);
}else if(xhr.readyState === 4 && xhr.status !== 200){
console.log(xhr.status);
}
}