引言:    

        在业务操作中,有一个数据是通过AJax请求回来的。而且这个数据在页面上会被操作。那么这个数据就需要存放到页面上,但是在通常的ajax方法是“异步”的,就会出现数据无法拿到。

        那么我们来举个例子演示一下,页面上有两个按钮,一个查询上一个月的积分,一个查询这个月的积分。在加载的数据时候,将上个月和本月的数据都加载了。

  <div  id="btndiv" style="height:100px;background-color:blue;" align="center" >

        <p id="jf" >积分:111</p>

        <p><button id="btn">上个月</button> <button id="btn1">本月</button></p>

    </div>

 编写Ajax方法,请求后台查询积分。采用通常的ajax方法,也就是异步的ajax 方法 async:true ,默认为true,可以在请求的时候不写这个参数

	$(function(){
		alert("第一:"+$("#jf").text()); 
		//定义一个全局变量
		var responseData ;
		//第一种方式: 将ajax 的异步请求设置为 false
		var requestData = {"name":"admin","passwd":"admin1"};
		$.ajax({	
			  url: "./jfdata.json", 	// 模拟请求action后响应的json数据
			  data:requestData,		// 请求的参数,可以是不同的形式
			  type: "GET",  		// 或者 POST
			  //dataType: "json",     // 预期服务器返回的数据类型。如果不指定,jQuery 将自动根据 HTTP 包 MIME 信息来智能判断,这里设置为 json
			  async:true, 			// 特别注意,同步请求将锁住浏览器,用户其它操作必须等待请求完成才可以执行。
			  success: function(result){  //请求成功后的响应函数
			 	//一般会强制将data转化为json对象
			  	//var redata = eval("(" + result + ")");
			  	responseData =  result;
				alert("第二"+result); 
				} 
			});
			console.log("异步情况打印:"+responseData);
			$("#jf").text(responseData == null?"值不存在":responseData.jf1);
			alert("第三次:"+$("#jf").text());
        	//上一月的点击事件
			$("#btn").click(function(){
				$("#jf").text(responseData == null?"值不存在":responseData.jf2);
			});
			//上一月的点击事件
			$("#btn1").click(function(){
				$("#jf").text(responseData == null?"值不存在":responseData.jf1);
			});
	});

这个  url: "./jfdata.json" 走的是本地的json文件

{"jf1":888,"jf2":666}

jf1 是本月的积分,jf2 是上个月的

我创建了全局变量    var responseData ; 来存放ajax请求后的数据,然后在方法外使用

按照之前的ajax请求,看下出现的效果。 注意其中写的 alert 弹窗

第一个 alert 在ajax方法之前执行,读取初始化的设置的积分值 111

第二个 alert 跨过了 ajax 方法, 并没有执行ajax方法,就执行了 jf 的赋值

第三个 alert 执行了ajax方法,拿到了请求的数据

这说明,默认的ajax 方法是异步请求,在整个页面加载后,才执行了ajax方法。 这并不是我们需要的效果。

解决问题方法1:修改ajax方法为 同步请求,在加载页面时,就去执行ajax 方法

设置 ajax 请求的  async:false 即可。

特别注意,同步请求将锁住浏览器,用户其它操作必须等待请求完成才可以执行。

但是这样会导致浏览器出现假死的情况。

在jquery的中文api 上也说明了这一点。

                强烈不建议把这个选项设置成false,这意味着所有的请求都不再是异步的了,这也会导致浏览器被锁死。

演示一下这样的情况:

假如我们需要在点击 “上个月” 的时候,请求后台,拿到一些其他数据,由于数据量比较大,请求耗时五秒。 并在请求时把 “上个月” 按钮改为 正在刷新,当数据成功返回改为“刷新成功”。 并且我们需要在 外部方法中使用这些数据,那么依然使用 同步的ajax 方法请求。

代码:

$(function(){
		$("#btn").live('click', function() {
			$("#btn").replaceWith('<button id="btn">正在刷新</button>');
			$("#btndiv").css("background","red");
			
			var responseData ;
			var requestData = {"name":"admin","passwd":"admin1"};
			$.ajax({	
				  url: "http://localhost:8080/AJaxResult/AjaxServlet", 	// 模拟请求action后响应的json数据
				  data:requestData,		// 请求的参数,可以是不同的形式
				  type: "GET",  		// 或者 POST
				  //dataType: "json",     // 预期服务器返回的数据类型。如果不指定,jQuery 将自动根据 HTTP 包 MIME 信息来智能判断,这里设置为 json
				  async:false, 			// 特别注意,同步请求将锁住浏览器,用户其它操作必须等待请求完成才可以执行。
				  success: function(result){  //请求成功后的响应函数
				  	responseData =  result;
					$("#jf").text("积分:"+responseData.totalRows);
					$("#btn").replaceWith('<button id="btn">刷新成功</button>');
					$("#btndiv").css("background","blue");
					$("#jf").text("积分:"+responseData.totalRows);
					} 
				});
				//alert(""+responseData);
		});
		});

servlet:

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		String data ="{\"datas\":[{\"child\":[],\"content\":\"体育新闻体育新闻体育新闻\",\"id\":1,\"name\":\"体育新闻\",\"parent\":null},{\"child\":[],\"content\":\"娱乐新闻娱乐新闻娱乐新闻\",\"id\":2,\"name\":\"娱乐新闻\",\"parent\":null},{\"child\":[],\"content\":\"时政新闻时政新闻时政新闻\",\"id\":3,\"name\":\"时政新闻\",\"parent\":null}]," +
				"\"pageNumber\":1,\"pageSize\":3,\"pageStartIndex\":0,\"totalPages\":8,\"totalRows\":22}";
		response.setCharacterEncoding("UTF-8");  
	    response.setContentType("application/json; charset=utf-8");  
	    new Thread(new Runnable() {
			
			public void run() {
				// TODO Auto-generated method stub
				System.out.println("执行线程");
				
			}
		}).start();
	    try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		PrintWriter out = response.getWriter();
		out.print(data);
		
	}

 

先看下使用ajax异步的情况:(正确的显示,但是无法将数据拿到外部方法中使用) async:true

看下使用ajax同步的情况:(不正确的显示,但是可以将数据拿到外部方法中使用)async:false

我们发现,在点击上个月之后,没有动静,直到五秒之后,才将数据变化。

原因:浏览器的渲染(UI)线程和js线程是互斥的,在执行js耗时操作时,页面渲染会被阻塞掉。当我们执行异步ajax的时候没有问题,但当设置为同步请求时,其他的动作(ajax函数后面的代码,还有渲染线程)都会停止下来。即使我的DOM操作语句是在发起请求的前一句,这个同步请求也会“迅速”将UI线程阻塞,不给它执行的时间

来源:https://wwwblogs/zengguowang/p/6188059.html

所以,需要使用别的方法解决这个问题:

(1)setTimeout 来解决

详情:https://wwwblogs/zengguowang/p/6188059.html

(2)将ajax同步的数据,赋值到页面的隐藏域中

 这个就是在同步请求的方法中,将数据赋值到页面中的隐藏域中,如果再次使用该数据,从隐藏域中将数据再拿出来使用。

隐藏域:

<input type="hidden" id="data" value="" />

ajax请求得到的数据:

$("#data").val(data);

再次使用这个数据:

	//1,从隐藏域中获取传回来的json数据
	 var data = $("#data").val();

但是这两种方法都不好。

最终解决办法:使用 jquery 提供的 Deferred

$(function(){
		
		$("#btn").live('click', function() {				
			$("#btn").replaceWith('<button id="btn">正在刷新</button>');
			$("#btndiv").css("background","red");
			$.when(getData()).done(function(result){
	            	//一般会强制将data转化为json对象
				  	//var redata = eval("(" + result + ")");
				  	var responseData =  result;
					$("#jf").text("积分:"+responseData.totalRows);
					$("#btn").replaceWith('<button id="btn">刷新成功</button>');
					$("#btndiv").css("background","blue");
					$("#jf").text("积分:"+responseData.totalRows);
	       		 }).fail(function(){
				 	 alert("$.get 失败!");
					  });
				});
			
			
			function getData(){		
				var defer = $.Deferred();   //创建一个新的 Deferred(延迟)对象
				//第一种方式: 将ajax 的异步请求设置为 false
				var requestData = {
					"name": "admin",
					"passwd": "admin1"
				};
				$.ajax({
					url: "http://localhost:8080/AJaxResult/AjaxServlet", // 模拟请求action后响应的json数据
					data: requestData, // 请求的参数,可以是不同的形式
					type: "GET", // 或者 POST
					//dataType: "json",     // 预期服务器返回的数据类型。如果不指定,jQuery 将自动根据 HTTP 包 MIME 信息来智能判断,这里设置为 json
					async: true, // 特别注意,同步请求将锁住浏览器,用户其它操作必须等待请求完成才可以执行。
					success: function(result){
						defer.resolve(result);  //解决Deferred(延迟)对象,并根据给定的参数调用任何 doneCallbacks 回调函数
						//这个函数会在 延迟对象即ajax 执行完毕后,在调用回调函数的时候 将参数值 result  传递给回调方法
					}
				});
				return defer.promise();  // 当ajax执行完毕,返回 Deferred 对象 
				//它创建一个promise对象,其目的是在未来某个时间点返回一个响应。
			}
		});

 

主要的步骤:

var defer = $.Deferred();   //创建一个新的 Deferred(延迟)对象

 

defer.resolve(data);  // data 异步的ajax响应的数据

 

return defer.promise();  // 当ajax执行完毕,返回 Deferred 对象 

 

$.when(getData()).done(function(result){ // 在ajax请求完后调用

                       responseData =  result;  // 将拿到的数据赋值到全局变量

               

                    }).fail(function(){  // 失败时调用

                   

                      });

   });

什么是deferred对象?

        开发网站的过程中,我们经常遇到某些耗时很长的javascript操作。其中,既有异步的操作(比如ajax读取服务器数据),也有同步的操作(比如遍历一个大型数组),它们都不是立即能得到结果的。

通常的做法是,为它们指定回调函数(callback)。即事先规定,一旦它们运行结束,应该调用哪些函数。

但是,在回调函数方面,jQuery的功能非常弱。为了改变这一点,jQuery开发团队就设计了deferred对象。

简单说,deferred对象就是jQuery的回调函数解决方案。在英语中,defer的意思是"延迟",所以deferred对象的含义就是"延迟"到未来某个点再执行。

来源:http://www.ruanyifeng/blog/2011/08/a_detailed_explanation_of_jquery_deferred_object

具体的细节,参考这几个网址:

https://wwwblogs/zengguowang/p/6188059.html

https://segmentfault/a/1190000007216755

http://wwwblogs/panmy/p/5651732.html

http://www.ruanyifeng/blog/2011/08/a_detailed_explanation_of_jquery_deferred_object

https://wwwblogs/panmy/p/5651732.html

看下效果:

Demo源码:https://download.csdn/download/qq_28817739/10602085 

更多推荐

在外部方法使用Ajax请求返回的数据