首页 » 前端开发 » 正文

用jQuery获取ajax返回值的多种方法

在很多应用场景中,我们会遇到通过ajax来获取值。一般来说,我们会直接在ajax的回调函数里边直接进行处理,但是在某些场景中需要将ajax的返回值传递出来,本文介绍3种可用的方法。每种方法都有自己的优缺点,读者可以自行考虑使用其中的一种。

先展示一下我们原始的函数,方便后文的描述:


function GetThings()
{
	$.post("XX.php",
		function(data){
			return data;
	});
}

为了方便读者能够跑起来,其XX.php内容可以如下(当然本地需要配置相关环境使之能够跑php文件)


echo "HelloWorld!";

*事实上,也可以直接写一个记事本文档(.txt),这样就不需要配置php环境了。

我们是希望通过这个GetThings()函数获取到某些数据,然后将其返回回来。

方法1:同步

我们知道,对于jQuery封装的$.post、$.get等方法默认都是异步传输的,所以如果对上面的GetThings()方法来说,执行 a = GetThings();是无法将ajax的返回值返回给a。解决方法就是将GetThings()方法改成同步:


function GetThings()
{
	$.ajax({
		url:"XX.php",
		async:false,
		type:"POST",
		success:function(data){
			return data;
		}
	});
}

此时通过a = GetThings();访问,发现还是没有返回值。原因在于,虽然改为同步了,但是其实GetThings()本身并没有返回值,所以最终的结果还是空,解决方案是将$.ajax的返回值保存起来返回回来:

function GetThings()
{       
	var t = undefined;
	$.ajax({
		url:"XX.php",
		async:false,
		type:"POST",
		success:function(data){
			t = data;
		}
	});
	return t;
}

这样就可以通过a = GetThings();访问到最终的值了(本例中即”Hello World!”)。稍微提醒一下的是,网上看到几篇文章对于同步给出了如下的代码,但是我测试不通过(本地采用jquery1.7.1的版本):

$.post("XX.php",{async:false},function(){...});

至此,该方法解决了接受ajax返回值的问题,其优点在于简单明了,理论上支持jQuery的各个版本;调用方式(a = GetThings();)符合最常规的逻辑。缺点在于,由于是同步,导致浏览器在执行GetThings()时处于一个浏览器假死的状态——直到数据返回才能继续执行该语句后面的代码,这意味着如果数据一直不返回,那么浏览器会一直等待数据,于是就一直在等待,此时浏览器就处于无响应状态。

方法2:回调函数

此方法思想就很简单了,实现起来也比较方便,直接上代码:


function GetThings(callback)
{
	$.post("XX.php",
		function(data){
			callback(data);
		});
}

此时,如果要接收返回的值,只需要在callback里边完成就行,具体的来说就是:


GetThings(function(data){
	t = data;
});

另外一个例子可以参看参考资料1。该方法简单明了,不存在浏览器卡死之类的情况,并且理论上支持所有版本的jQuery,比起方法1可能就调用时没有那么直观,其他没有什么缺点。

方法3:Deferred对象

这个方法相对前两个方法来说比较高级,但是思路比较简单,就是采用Deferred对象。

Deferred对象,简单说,Deferred对象就是jQuery的回调函数解决方案。我们经常遇到某些耗时很长的javascript操作。其中,既有异步的操作(比如ajax读取服务器数据),也有同步的操作(比如遍历一个大型数组),它们都不是立即能得到结果的。通常的做法是,为它们指定回调函数(callback)。即事先规定,一旦它们运行结束,应该调用哪些函数。但是,在回调函数方面,jQuery的功能非常弱。为了改变这一点,jQuery开发团队就设计了Deferred对象。在英语中,defer的意思是”延迟”,所以deferred对象的含义就是”延迟”到未来某个点再执行。Deferred对象从jQuery1.5开始引入,并且jQuery团队改写了诸如ajax等方法,在1.5之前,$.ajax会返回XHR对象;而则之后,返回一个Deferred对象。比如原来的$.post方法可以像前文描述的方式写:


$.post("XX.php",
	function(data){
		callback(data);
	});

如果你的jQuery版本>=1.5可以采用如下方式:


$.post("XX.php").done(function(data){
	callback(data);
});

即可以把回调函数拿出来放在最后边。因为$.post返回Deferred对象,而该对象支持链式方法,其.done()方法表示前者已完成时的处理(Deferred对象有3种状态,即未完成,已完成和已失败)。对于Deferred对象可以参见参考资料2,该文章很清晰地解释了该对象,当然也可以参看官方文档给出的信息

我们原始的设想是,希望在GetThings()执行完之后将其值拿出来。Deferred对象能够检测到自身的完成状态,并在完成时继续执行完成后的代码,此处修改原始方法如下:


function GetThings()
{
	var def = $.Deferred();
	$.post("XX.php",
		function(data){
			return def.resolve(data);
		}
	});
	return def.promise();
}

此处在GetThings()中新建了一个Deferred对象,同时该函数返回了该Deferred.promise()。该方法是记录该Deferred对象是否已经完成,而Deferred.resolve()将手动修改该对象为已完成状态。当然如果你愿意可以把该函数按照前文所述改成链式:

$.post("XX.php").done(function(data{callback(data);});

由于GetThings()返回了一个Deferred对象,所以要获取其数据可以链式地用.done()方法调用:

GetThings().done(function(data){
	var t = data;
});

该方法的缺点在于对开发者要求相对较高,必须了解Deferred对象,而且该方法仅适用于jQuery1.5及以上版本,但是jQuery团队发明了该对象,并且重写了ajax部分,可见其重要性,而且可以说是一个趋势。Deferred对象从某种意义上来说是对回调函数的一种优化,可以看到Deferred代码编写更符合人的一般思维。

参考资料

1. 《How can I get the return value of jquery post function?

2.《jQuery的deferred对象详解

发表评论