蒟蒻对于ajax底层原理的摸索


Ajax技术:由浏览器提供的一套方法,可以实现页面无刷新更新数据,提高用户浏览网站应用的体验。不是一门新技术,而是利用js函数来操作数据的传输与获取,实现局部更新。

Ajax技术运行环境:Ajax需要运行在网站服务器环境中才能生效

ajax的运行原理

Ajax技术运行原理:Ajax相当于浏览器发送请求与接收响应的代理人,以实现在不影响用户浏览页面的情况下,局部数据更新数据,从而提高用户体验。
在这里插入图片描述

Ajax的实现步骤

(在JavaScript函数中创建)
1.创建Ajax对象

var xhr=new XMLHttpRequest();

2.告诉Ajax请求地址以及请求方式
//这里open里面还有第三个参数,是设置是否异步的,默认为true,即异步。如果设置为false,则为同步了。
在这里插入图片描述

xhr.open('get','http://www.example.com');

3.发送请求

xhr.send();//发送请求,如果你不主动发送,是不会发送的

4.获取服务器端与客户端的响应数据
请求的获取不能理解在send()方法之后,因为传输是需要时间的

xhr.onload=function(){
console.log(xhr.responseText);
}

当服务器端对客户端作出了响应,浏览器就会自动调用xhr对象下面的onload事件对应的事件处理函数,在事件处理函数中,就可以获取服务器端返回给客户端的数据。
一般返回的结果会是一个对象,但服务器端会把它转化为一个字符串,我们需要自己将这个字符串转化为对象

//xhr.οnlοad=function(){
//xhr.responseText 这个东西本质上是一个对象转化而成的字符串,我们需要将它转化为对象才可以使用
//}
xhr.onload =function(){
var responseText = JSON.parse(xhr.responseText)
console.log(responseText);//输出,这个时候 responseText就是一个对象了
var str='<h2>'+responseText.name+'</h2>';//获得对象responseText中的name属性的值
document.body.innerHTML=str;//往html页面追加一个str,这个时候,就可以看到获得的数据了
}

在这里插入图片描述

传统请求方式与ajax请求的对比

传统网站都是请求数据都是通过表单的方式传递的,只要表单提交,表达内容会被变成参数自动拼接到对应的位置。请求数据都是 参数名称=参数值 多个参数之间用 & 进行分割。
利用ajax技术,我们要自己将请求参数凭借到对应位置。参数格式还是 参数名称=参数值 的形式 多个参数用 & 进行分割
对于GET请求,参数被拼接在请求地址后面,请求地址和第一个请求参数用 进行分割。

GET方式:
在这里插入图片描述
html代码:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>查询信息</title>
	<script style="text/javascript" src="js/query.js"></script>
</head>
<body>
<h1 align="center">查询页面</h1>
    <input type="text" id="username">
    <input type="password" id="password">
    <input type="button" value="提交" onclick="show()">
</body>
</html>

js代码:

//为按钮添加点击事件
		function show() 
		{
			//获取姓名文本框
			var username=document.getElementById('username');
			
			//获取密码文本框
			var password=document.getElementById('password');
			
            //创建ajax对象
            var xhr=new XMLHttpRequest();

            //获取用户在文本框中输入的值
            var usernameValue=username.value;
            var passwordValure=password.value;
            
			//拼接请求参数,注意参数之间的 & 和 地址和第一个参数之间的 ? 不要忘记
			var params='username='+usernameValue+'&password='+passwordValure;
            //配置ajax对象
            xhr.open('get','http://localhost:8080/demo1?'+params);
            //告诉请求方式,请求地址以及请求参数
			xhr.send();//发送请求
			//获取服务器端响应的数据!
			xhr.onload =function(){
				console.log(xhr.responseText)
			}

        }

POST请求方式:
POST的请求参数不是放在地址栏之中,而是放在请求体之中。post需要设置请求参数的格式
如果是以 参数名=参数值 这种形式传递的,那它就是下面这一句固定的话
在这里插入图片描述
js代码:

//为按钮添加点击事件
		function show() 
		{
			//获取姓名文本框
			var username=document.getElementById('username');
			
			//获取密码文本框
			var password=document.getElementById('password');
			
            //创建ajax对象
            var xhr=new XMLHttpRequest();

            //获取用户在文本框中输入的值
            var usernameValue=username.value;
            var passwordValure=password.value;
            
			//拼接请求参数,注意参数之间的 & 和 地址和第一个参数之间的 ? 不要忘记
			var params='username='+usernameValue+'&password='+passwordValure;
            //配置ajax对象
            xhr.open('POST','http://localhost:8080/demo1');
			
			//设置请求参数的格式(POST请求必须要设置)	
			xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded')
			xhr.send(params);//发送请求
			//获取服务器端响应的数据
			xhr.onload =function(){
				console.log(xhr.responseText)
			}

        }


请求参数格式

1.参数名=参数值 application/x-www-form-urlencoded

name=zhansan&sex=

2.参数名:‘参数值’ application/json

{name:'lisi',age:'20'}

注意:get方式是不能够使用json对象数据格式的,传统网站的表单提交也是不支持json格式的
POST利用第二种传输格式进行传输时,要把Content-Type 的值 改为由application---->json,告诉服务器当前请求的格式是json。 我们还需要将json对象转化为json字符串然后再放置在send()方法中,因为传递请求参数时,参数必须以字符串的形式进行传递。
JSON.stringify()//将json对象转化为字符串

html代码:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>查询信息</title>
	<script type="text/javascript" src="js/query01.js"></script>
</head>
<body>
<input type="text" id="username">
<input type="password" id="password"/>
<input type="button" id="btn" value="提交"  onclick="show()"/>
</body>
</html>

js代码:

function show() 
		{
			//获取姓名文本框
			var username=document.getElementById('username');
			
			//获取密码文本框
			var password=document.getElementById('password');

            //获取用户在文本框中输入的值
            var usernameValue=username.value;
            var passwordValure=password.value;
			//创建ajax对象		
			var xhr=new XMLHttpRequest();
          	xhr.open('POST','http:localhost:8080/json')
          	xhr.setRequestHeader('Content-Type','application/json');
          	xhr.send(JSON.stringify({username:usernameValue,password,passwordValure}))
        }

下面这种方式是有点过时的,但是现在依然大量存在。
既然传了数据给数据库,那么我们也就需要把所响应的数据从服务器上拿下来。
如果要兼容ie低版本浏览器,就需要使用这种方法。

ajax状态码:在创建ajax对象,配置ajax对象,发送请求,以及接收完服务器响应数据这个过程中每一个步骤都会对应一个数值,这个数值就是ajax状态码。
0:请求为初始化,还没有地用用open()
1:请求已经建立,但是还没有发送(没有调用send())
2:请求已经发送
3:请求已经正在处理中,通常响应中已经有部分数据可以用了
4:响应已经完成,可以获取并且使用服务器的响应了


xhr.readyState//获取状态码,也可以写一个 xhr.readySaste=function(){}
xhr.status//获取http状态码,当xhr.status==200的时候,就表明所获得的东西都是你想要的。


onreadystatechange事件
当ajax状态码发生改变时触发
这种需要通过onreadystatechange事件来监听ajax的状态码,如果ajax状态码等于4,那么我们就可以对响应数据进行操作了。
js代码:

function(){
	var xhr=new XMLHttpRequest();
	//0已经创建但是还没有对ajax对象进行配置
	console.log(xhr.readyState)
	xhr.open('GET','http://localhost:3000/readeysatge')
	//1,已经对ajax对象进行配置,但是还没有发送请求
	console.log(xhr.readyState)
	

	
	//当ajax状态码发生变化的时候触发
	//2代表请求已经发送
	//3代表已经接收到服务器的部分数据
	//4服务器端的响应数据已经接受完成
	xhr.onreadystatechange=function(){
		console.log(xhr.readyState)
	}
	//对ajax代码进行判断,如果ajax状态码等于4,那我们就代表数据已经接受完成了
	xhr.send();
}

在这里插入图片描述


ajax错误处理

通过 xhr.status 可以获得对应的http状态码,可以进行对应的提示
js代码:
1.网络畅通,服务器能接收到请求,服务器返回的结果不是预期的结果。

function error_test(){
	var xhr=new XMLHttpRequest();
	xhr.open('GET','http://local:host/error')
	xhr.send();
	xhr.onload=function(){
		//xhr.status 获取http状态码,处理一些异常情况
		console.log(xhr.responseText);
		//console.log(xhr.status)//状态码
		
		if(xhr.status==400)
		{alert('请求出错')}
	}
}

2.网络畅通,服务器没有接收到请求,返回404状态码
   检查请求地址是否发生错误
3.网络畅通,服务器能接收客户端请求,但是服务器出错,返回500状态码
(找服务器的后端程序员进行沟通)
4.网络中断,请求无法发送到服务器端。
不会触发xhr对象下面的onload事件,但是会触发xhr对象下面的onerror事件,在onerror事件处理函数中对错误进行处理。
js代码:

		//当网络中断时会触发onerror事件
		xhr.onerror=function(){
			alert('网络中断,无法发送ajax请求')
		}

Ajax状态码:表示Ajax请求的过程状态,ajax对象返回的
Http状态码:表示请求的处理结果

解决低版本IE浏览器的缓存问题

在低版本的IE浏览器中,Ajax有严重的请求缓存问题,即请求地址不发生改变的情况下,只有第一次请求会真正的发送到服务器,后续的请求都会从浏览器中获取,即是服务器的数据已经更新了,客户端依然拿到的是缓存中的旧数据。
解决方案:在请求的地址后面加上请求参数,保证每一次请求的参数不相同。
注意:传入的改变参数名称不能与要传输的参数的名称一致

xhr.poen('get','http://localhost:8080/demo?t='+Math.random())

Ajax异步编程

同步:一行代码执行完成后,才能执行下一行代码
例子:一个人同一时间只能做一件事情,只有做完一件事情之后,才能做另外一件事情。
异步
异步:异步代码需要花时间去执行,但是程序不会等待异步代码执行完成后再继续执行后续代码,而是直接执行后续代码,当后续代码执行完成之后,再回头看看异步代码是否返回结果。如果已经有返回结果,再用事先准备的回调函数处理异步代码执行的结果。(JavaScript中的onload就是回调函数中的一种函数)
例子:一个人一件事情做了一半,转而去做另外一件事情,等其他事情做完之后,再回过头来做之前未完成的事情。

照正常来说,我们是从上往下执行代码,那么就是先输出2再输出1。但是在执行到onload事件时,因为传送数据需要时间,所以程序会立即执行接下来的代码,就是先输出1,然后再回去执行回调事件(onload),再输出2.

xhr.onload=function(){
console.log(2)
}
console.log(1)

ajax函数封装:因为每个ajax函数都是大同小异的,我们要将那些功能性相同的重复性代码封装为一个函数,使用时直接调用就好了,不用每次都去做一些重复性的代码编写工作。
思想:我们要将那些只有在传输之前才能确定的数据作为参数传进去这个函数中,然后那些确定的东西就可以一直复用了。


封装

ajax封装01:
此时,我们先不考虑请求要发送的参数,此时,我们需要传进去的参数有要传输的方式(get/post),传输的地址url,然后,我们传输之后,需要对服务器返回的结果字符串也就是xhr.responseText做进一步的处理,但是这个处理的过程也是不相同的,例如要打印或者其他操作。所以,这个对于结果的处理还是得交由用户来处理,所以也要传入一个参数来操作结果。
调用形参options的success属性(success属性封装着一个函数,那就是作为结果处 理的函数,然后,我们要将服务器返回的字符串作为参数传递给success函数,这样它才能获得要处理的结果字符串)进行对结果的处理。

function register(options){
    var username=document.getElementById("username");
    var userpassword=document.getElementById("userpassword");
    var usernameValue=username.value;
    var userpasswordValue=userpassword.value;

    var xhr=new XMLHttpRequest();
    var params='username='+usernameValue+'&userpassword='+userpasswordValue;
    xhr.open(options.type,options.url);
    xhr.send();
    xhr.onload=function () {
        options.success(xhr.responseText);
        //调用形参options的success属性(success属性封装着一个函数,那就是作为结果处			理的函数,然后,我们要将服务器返回的字符串作为参数传递给success函数,这样它才能获得要处理的结果字符串,才能进行下一步的处理)
    }
}
    register(
        {
            type:'get',
            url:'http://localhost:8080/registerServlet',
            success:function (data) {console.log(data)}})

ajax封装02:
因为post的参数传递形式是要在send()方法中的,所以如果利用形参来处理的话,是不能够将参数直接附加在请求的url地址后面的。这样的话,get方法所要传递的参数也是不能够直接附着在请求的url里面的,需要另寻他法。

请求参数要考虑的问题:
1.请求参数的位置问题:将请求参数传递到ajax函数内部,在函数内部根据请求方式的不同将请求参数放在不同的位置
get:放在请求地址后面
post:放在send()方法中
2.请求参数格式问题
(1)application/x-www-form-urlencoded(参数名称=参数值&参数名称=参数值)
例如:name=zhangsan&age=20
(2)application/json
{name:‘zhangsan’,age:20}
1.传递对象数据类型对于函数的调用者更加友好
2.在函数内部对象数据类型转换为字符串类型更加方便

踩的雷

1.顺序,顺序很重要,就是创建ajax对象,然后open,然后send,再onload处理结果
2.传的参数很重要,多利用alert()函数来打印数值,特别是传地址和参数的时候
html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>register</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <script type="text/javascript" src="../js/register.js"></script>
</head>
<body>
账号:<input type="text" name="username" id="username">
密码:<input type="password" name="userpassword" id="userpassword" >
<input type="button" value="登录" onclick="register()">
</body>
</html>

js代码:

function register(options){
    //创建ajax对象
    var xhr=new XMLHttpRequest();

    //拼接请求参数的变量
    var params='';
    //循环用户传递进来的对象参数格式
    for (var attr in options.data)
    {
        params+=attr+'='+options.data[attr]+'&'
    }
    params= params.substring(0,params.length-1);//去掉最后一个&

    //判断请求方式
    if(options.type=='get'){
        options.url=options.url+'?'+params;
    }

    xhr.open(options.type,options.url);//先open,然后才能发送数据

    if(options.type=='post'){
        //设置请求参数格式类型,post以这种 参数名=参数值的形式需要设置
        xhr.setRequestHeader('Content-type','application/x-www-form-urlencoded')
        xhr.send(params);
    }
    if(options.type=='get')
    {
        xhr.send();
    }

}
register(
    {
        type:'get',
        url:'http://localhost:8080/registerServlet',
        //要传递的参数
        data:{
            unsername:'zhangsan',
            userpassword:'123456'
        },
        //结果处理函数
        sucess:function (data) {
            console.log(data)
        }
    }
)

ajax封装03:
用户想要传递的参数格式在上面被我们设置为application/x-www-form-unlended
如果用户想要设置的参数不是这个而是json呢?把content-Type作为一个参数传进去。因为Content-Type中间有个很杠,在js里面是非法的。所以要获取它的值,就是要:options.header[‘Content-Type’]
js代码:

function register(options){
    //创建ajax对象
    var xhr=new XMLHttpRequest();

    //拼接请求参数的变量
    var params='';
    //循环用户传递进来的对象参数格式
    for (var attr in options.data)
    {
        params+=attr+'='+options.data[attr]+'&'
    }
    params= params.substring(0,params.length-1);//去掉最后一个&

    //判断请求方式
    if(options.type=='get'){
        options.url=options.url+'?'+params;
    }

    xhr.open(options.type,options.url);//先open,然后才能发送数据

    if(options.type=='post'){
        //用户希望的向服务器端传递的请求参数的类型
        var contentType=options.header['Content-Type']
        //设置请求参数格式类型,post以这种 参数名=参数值的形式需要设置
        xhr.setRequestHeader('Content-Type',contentType);
        //判断用户希望的请求参数的格式类型

        if(contentType=='application/json'){
            //如果类型为json,就像服务器端传递json格式的参数
            xhr.send(JSON.stringify(options.data))
        }
        else
        {
            //如果类型是普通的,那就向服务器传递普通的参数
            xhr.send(params);
        }
    }
    if(options.type=='get')
    {
        xhr.send();
    }

}
register(
    {
        type:'post',
        url:'http://localhost:8080/registerServlet',
        //要传递的参数
        header:{
            'Content-Type':'application/json'
        },
        data:{
            unsername:'zhangsan',
            userpassword:'123456'
        },

        //结果处理函数
        sucess:function (data) {
            console.log(data)
        }
    }
)

总结:ajax底层差不多就是这样实现的,主要步骤就是上面提到的那些步骤。不过在日常工作中,我们并不直接使用如此底层的编码方式,有许多优秀的开源框架里面封装好了这个功能,我们直接调用即可,我们自己写的可能一些兼容性问题或者什么都没有很好的考虑到,但是对于底层还是要了解一点【源码之下无秘密】

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值