我们知道,ajax是一种异步请求的方式,想要了解异步请求,就必须要先从同步请求说起。
同步请求原理
常见的同步请求的方式是form表单的提交,我们先从一种同步请求的示例说起。我们希望输入姓名可以从后台得到身份证号:
case那么用同步请求的方式要这么做
前端代码:
<form action="" id = "formId">
<input type="button" id="testBtn" value="测试按钮" onclick="sentSyn();"/><br>
姓名:<input type="text" name = 'name' value=""/><br>
身份证号:<input type="text" name = 'ID' value="${ID }"/><br>
</form>
<script type="text/javascript">alert(111);
function sentSyn(){
document.getElementById("formId").action = "<%=basePath %>/manage/test/syn";
document.getElementById("formId").submit();
}
</script>
后台代码:
@RequestMapping("/syn")
public void testSyn(HttpServletRequest request, HttpServletResponse response){
try {
request.setAttribute("ID", "12345");
request.getRequestDispatcher("/ajax.jsp").forward(request, response);
} catch (ServletException | IOException e) {
e.printStackTrace();
}
}
姓名输入"小明" 点击按钮页面上的效果是这样的:
alert(111)先弹了出来,说明页面重新加载了一次,而且得到小明的身份证号后,名字不见了,原先的数据消失了。要解决这个问题,你用同步请求的方式也是可以的,
在你的后台代码里加上一行:request.setAttribute("name", request.getParameter("name"));就可以实现数据的回显。但是弹框还是会出现,说明页面又一次加载了。
由此我们可以推断出同步请求是怎么跟服务器进行数据交互的。使用同步请求,服务器将响应的数据直接输送给浏览器的内存,导致覆盖浏览器内存中原有的数据,浏览器接收到响应的数据后只能展示服务器端返回的数据,无法展示发送请求之前在浏览器中添加的数据。
当你使用同步请求与服务器进行数据交互的时候,浏览器是直接面对服务器的,也就是在服务器处理请求的过程中浏览器处于等待,卡死的状态,你无法在页面上进行其他的操作。而且当页面信息量较大时,你使用同步请求与服务器进行数据交互,又要回显页面上众多的数据时,你的后台代码将会写的很麻烦既要处理数据的回显又要处理请求,增加服务器的压力。
当然同步请求也有他的优点,当你页面上需要与服务器的数据交互的操作较少时或者需要回显的数据较少时,推荐使用同步,因为它是直接与服务器进行数据交互的。仁者见仁智者见智,具体问题具体分析,要根据你的使用场景进行选择。
异步请求原理的分析
我们知道,在同步请求模型中,浏览器是直接向服务器发送请求,并直接接收、处理服务器响应的数据的。这就导致了浏览器发送完一个请求后,就只能干等着服务器那边处理请求,响应请求,在这期间其它事情都做不了。这就像是你到了一个新城市去找房子住,你可以自己去找,在网站上或者是街头小广告上去了解房源信息,找合适自己的那一个,然后去跟房东谈价钱。在这期间你的精力和时间大部分都用到了找房子上,你可能没时间再去找工作或者做其他的事情了。还有一种方式是你找一个租房中介,找你一个代理人,把你的需求告诉他让他来帮你找,在中介给你找房子的同时你还可以去找工作或者做其他的事情。
异步请求正是基于以上所述的模式,浏览器把请求交给代理对象—XMLHttpRequest(绝大多数浏览器都内置了这个对象),由代理对象向服务器发起请求,接收、解析服务器响应的数据,并把数据更新到浏览器指定的控件上。从而实现了页面数据的局部刷新。异步请求使浏览器不用等待服务器处理请求,不用重新加载整个页面来展示服务器响应的数据,在异步请求发送的过程中浏览器还能进行其它的操作。一些语言采用了开一个子线程并把耗时操作放到子线程去执行的办法解决了这个问题。js引擎本身不支持多线程,但是浏览器基本上都有三个线程:js引擎线程、事件触发线程、http请求线程。后两个线程在触发后会把对应的回调函数放到js引擎线程的执行队列中进行排队等待,只要js引擎线程空闲就会依次执行加入到队列中的回调函数。当然这些回调函数的执行依然是阻碍线程的。
我们来看一下异步请求的执行流程图:
下面我们用原生的ajax请求的代码实现一下一个例子。输入姓名,页面局部刷新身份证号。
<input type="button" id="testBtn" value="测试按钮" onclick="sentAjax();"/><br>
姓名:<input type="text" name = 'name' value=""/><br>
身份证号:<input type="text" name = 'ID' id="ID" value=""/><br>
<script type="text/javascript">
alert(111);function sentAjax(){
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("get","<%=basePath %>/manage/test/ajax",true);
xmlHttp.send();
xmlHttp.onreadystatechange = function (){
var state = xmlHttp.readyState;
var status = xmlHttp.status;
if(state == 4 && status == 200){
var data=xmlHttp.responseText;
document.getElementById("ID").value = data;
}
}
}
</script>
服务器代码
@RequestMapping("/ajax")
public void testAjax(HttpServletRequest request, HttpServletResponse response){
try {
response.setCharacterEncoding("utf-8");//响应字符集的编码格式
PrintWriter out=response.getWriter();
out.print("12345");
} catch (IOException e) {
e.printStackTrace();
}
}
点击按钮看一下执行结果:
点击之前 点击之后
异步请求发送后,原来页面上的的数据没有消失,alert(111),没有弹出,说明页面没有重新加载只是局部刷新了。(顺便提一句,这里没有中文乱码的问题,一是姓名参数没有与服务器进行交互,二来更加说明,页面没有重新加载)
下面我们看一下,ajax请求中对于各项参数的解释。
var xmlHttp = new XMLHttpRequest();//用于创建代理对象
xmlHttp.open("get","<%=basePath %>/manage/test/ajax",true);//初始化请求
xmlHttp.send();//发送请求
方法列表
xmlHttp.onreadystatechange//监听请求的状态
监听请求的状态var data=xmlHttp.responseText; //获取相应文本格式
文本格式
网友评论