使用JQuery Deferred对象的then() 解决多个AJAX操作顺序依赖的问题

之前的文章"javascript异步代码的回调地狱"中提到了编写AJAX代码经常遇到的3个问题,现在我们看下如何利用then()解决第2个问题:如果AJAX请求之间存在依赖关系,我们的代码就会形成Pyramid of Doom(金字塔厄运)。比如我们要完成这样一件事:有4个供Ajax访问的url地址,需要先Ajax访问第1个,在第1个访问完成后,用拿到的返回数据作为参数再访问第2个,第2个访问完成后再第3个...以此到4个全部访问完成。按照这样的写法,似乎会变成这样:

$.ajax({  
    url: url1,  
    success: function(data){  
        $.ajax({  
            url: url2,  
            data: data,  
            success: function(data){  
                $.ajax({  
                    //...  
                });  
            }      
        });  
    }  
});

1.Deferred.then()相当于Deferred.done()、Deferred.fail()、Deferred.progress()的合体,可以同时注册3个状态下的回调函数。
function success(data)
{
	alert("success data = " + data);
}

function fail(data)
{
	alert("fail data = " + data);
}

function progress(data)
{
	alert("progress data = " + data);
}

var deferred = $.Deferred();

// 一起注册回调
deferred.then(success, fail, progress);

// 分别注册回调
deferred.done(success);
deferred.fail(fail);
deferred.progress(progress);

deferred.notify("10%");
deferred.resolve("ok");  
当然我们也可以像done()一样,多次调用then()注册回调函数。then()虽然可以这么使用,但是实际开发中一般不这么用,因为没有啥必要。JQuery1.8之前,这就是then()方法的作用。

2.Deferred.then()解决多个异步操作之间有依赖的问题,这才是then()真正有意义的场景。JQuery1.8之后,then()取代了过时的pipe()方法。这种场景下,我们需要使用Deferred.then()返回的新Promise对象。上面的第一种使用方式,我们忽略了Deferred.then()的返回值。

var deferred = $.Deferred();

// 使用then()注册一个resolved状态的回调函数,并返回一个过滤后的promise
// 返回的filtered已经不是原来的Deferred或者Promise对象了
var filtered = deferred.then(function( value ) {
				alert("trigger Deferred filter.value="+value);//5
				return value * 2;
			});

// 用过滤后的Promise再次注册回调函数			
filtered.done(function( value ) {
    alert("filtered value=" + value);//10
});
 
deferred.resolve( 5 );

我们用deferred.then()注册了一个完成状态下的回调函数,这个回调函数得到的值是5;之后用filtered这个新的Promise注册回调函数,这个回调函数中得到的值是10(第一个回调函数的返回结果)。现在我们看下JQuery官方对then的解释:

These filter functions can return a new value to be passed along to the promise's .done() or .fail() callbacks, or they can return another observable object (Deferred, Promise, etc) which will pass its resolved / rejected status and values to the promise's callbacks. If the filter function used is null, or not specified, the promise will be resolved or rejected with the same values as the original.

我们知道deferred.resolve()、deferred.reject()、deferred.notify()可以指定参数值,这个参数会传递给相应状态下的回调函数。如果我们使用的是done()、fail()、progress()注册的回调函数,那么某个状态下的所有回调函数得到的都是相同参数。但是如果我们使用了then()注册回调函数,那么第一回调函数的返回值将作为第二个回调函数的参数,同样的第二个函数的返回值是第三个回调函数的参数。可以对比下面的2段代码,体会下done()和then的差别。

var deferred = $.Deferred();

// done()返回的仍然是原来的Deferred对象
var done_ret = deferred.done(function(data){
	alert("data="+data);//5
	return 2 * data;
});
alert(deferred == done_ret);//true

done_ret.done(function(data){
	alert("data="+data);//5
});

deferred.resolve( 5 );


var deferred = $.Deferred();

// then()返回的是一个新Promise对象
//then注册的回调函数的返回值将作为这个新Promise的参数
var then_ret = deferred.then(function(data){
	alert("data="+data);//5
	return 2 * data;
});
alert(then_ret == deferred);//false

then_ret.done(function(data){
	alert("data="+data);//10
});

deferred.resolve( 5 );

同样地,Deferred.then也能够实现rejected和pending状态的回调函数过滤。
var defer = $.Deferred();
var filtered = defer.then( null, function( value ) {
    return value * 3;
  });
 
defer.reject( 6 );

filtered.fail(function( value ) {
  alert( "Value is ( 3*6 = ) 18: " + value );
});


下面这段代码可以实现chain tasks,解决异步操作中回调难的问题。

var defered = $.Deferred();

var promise1 = defered.then(function(data){
	alert(data);//
	return data+="1";
});

var promise2 = promise1.then(function(data){
	alert(data);//1
	return data+="2";
});

var promise3 = promise2.then(function(data){
	alert(data);//12
	return data+="3";
});

promise3.done(function(data){
	alert(data);//123
});

defered.resolve("");

正是由于then()这个特性,我们就可以上面复杂的AJAX嵌套改成如下形式:
var promise1 = $.ajax(url1);
var promise2 = promise1.then(function(data){
	return $.ajax(url2, { "data": data });
});
var promise3 = promise2.then(function(data){
	return $.ajax(url3, { "data": data });
});
promise3.done(function(data){
	// data retrieved from url3
});


  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
jQuery 中的 Deferred 对象提供了一种优雅的方式来处理异步操作,它可以让我们更方便地控制异步操作的状态和执行顺序。下面是 Deferred 对象的常用方法: 1. $.Deferred():创建一个 Deferred 对象。 2. deferred.done():当 Deferred 对象的状态变为已完成时,调用该方法注册的回调函数。 3. deferred.fail():当 Deferred 对象的状态变为已失败时,调用该方法注册的回调函数。 4. deferred.always():无论 Deferred 对象的状态是已完成还是已失败,都调用该方法注册的回调函数。 5. deferred.then():当 Deferred 对象的状态变化时,调用该方法注册的回调函数。它可以接受两个参数,第一个参数是已完成状态的回调函数,第二个参数是已失败状态的回调函数。 6. deferred.promise():返回一个 Promise 对象,该对象可以被传递给其他函数或者方法,但只能调用 then()、catch() 和 finally() 方法,不能改变 Deferred 对象的状态。 下面是一个使用 Deferred 对象的示例代码: ```javascript function asyncAction() { var defer = $.Deferred(); setTimeout(function() { defer.resolve("Async Action Completed!"); }, 2000); return defer.promise(); } var promise = asyncAction(); promise.then(function(data) { console.log(data); }).fail(function() { console.log("Async Action Failed!"); }).always(function() { console.log("Async Action Done!"); }); ``` 在这个例子中,我们定义了一个 asyncAction() 函数,它返回一个 Deferred 对象。在该函数内部,我们使用 setTimeout() 函数模拟一个异步操作,并在两秒后调用 resolve() 方法,将 Deferred 对象的状态设置为已完成。然后我们使用 promise 变量保存该 Deferred 对象的 Promise 对象,并使用 then()、fail() 和 always() 方法注册回调函数。在 then() 方法中,输出异步操作完成的信息;在 fail() 方法中,输出异步操作失败的信息;在 always() 方法中,输出异步操作完成的信息。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值