上一篇文章"JQuery.deferred提供的promise解决方式",提到了javascript异步操作的3个问题,以及javascript Promise入门。如今我们看下怎样利用$.when()来解决上一篇博客中的第3个问题。

考虑这样的场景。假如我们同一时候发送两个Ajax请求,然后要在两个请求都成功返回后再做一件接下来的事,想一想假设仅仅按前面的方式在各自的调用位置去附加回调,这是不是非常困难?

使用when(),我们能够通过类似以下的代码解决问题。

以下这段代码能够实现这个效果:当ajax1和ajax2操作都成功的时候。会调用onDone回调函数。

var promise1 = $.ajax(url1),
promise2 = $.ajax(url2),
promiseCombined = $.when(promise1, promise2);
promiseCombined.done(onDone);

$.when()方法能够合并多个Promise得到一个新的Promise,相当于在原多个Promise之间建立了AND(逻辑与)的关系。假设全部组成Promise都已成功,则令合并后的Promise也成功。假设有随意一个组成Promise失败,则马上令合并后的Promise失败。


1.$.when()不传參数,或者參数既不是Deferred对象也不是Promise对象。

这样的场景没有什么实际作用。

If a single argument is passed to jQuery.when() and it is not a Deferred or a Promise, it will be treated as a resolved Deferred and any doneCallbacks attached will be executed immediately. The doneCallbacks are passed the original argument. In this case any failCallbacks you might set are never called since the Deferred is never rejected. For example:

$.when( { testing: 123 } ).done(function( x ) {
  alert( x.testing ); // Alerts "123" immediately
});

If you don't pass it any arguments at all, jQuery.when() will return a resolved promise.
$.when().done(function( x ) {
  alert( "I fired immediately" );//x is undefined
});

2.$.when()仅仅有1个參数。该參数是Deferred或者Promise对象。

If a single Deferred is passed to jQuery.when(), its Promise object (a subset of the Deferred methods) is returned by the method. Additional methods of the Promise object can be called to attach callbacks, such as deferred.done. When the Deferred is resolved or rejected, usually by the code that created the Deferred originally, the appropriate callbacks will be called. For example, the jqXHR object returned by jQuery.ajax() is a Promise-compatible object and can be used this way:

$.when( $.ajax( "test.aspx" ) ).done(function( data, textStatus, jqXHR ) {
  alert( jqXHR.status ); // Alerts 200
});

// 创建1个延迟对象
var dtd = $.Deferred();

// 返回这个延迟对象的Promise
var its_promise = $.when(dtd);

// 能够利用promise绑定各种回调函数
its_promise.done(function(){alert("success");});

// 改变状态仅仅能通过Deferred对象
dtd.resolve();

3.$.when()參数是多个Deferred或者Promise对象。这样的场景才是when()真正的价值所在。

In the case where multiple Deferred objects are passed to jQuery.when(), the method returns the Promise from a new "master" Deferred object that tracks the aggregate state of all the Deferreds it has been passed. The method will resolve its master Deferred as soon as all the Deferreds resolve, or reject the master Deferred as soon as one of the Deferreds is rejected. If the master Deferred is resolved, the doneCallbacks for the master Deferred are executed. The arguments passed to the doneCallbacks provide the resolved values for each of the Deferreds, and matches the order the Deferreds were passed to jQuery.when(). For example:

var d1 = $.Deferred();
var d2 = $.Deferred();
 
$.when( d1, d2 ).done(function ( v1, v2 ) {
    console.log( v1 ); // "Fish"
    console.log( v2 ); // "Pizza"
});
 
d1.resolve( "Fish" );
d2.resolve( "Pizza" );
这就是相当于2个Promise进行逻辑与操作,得到1个新的Promise。

In the event a Deferred was resolved with no value, the corresponding doneCallback argument will be undefined. If a Deferred resolved to a single value, the corresponding argument will hold that value. In the case where a Deferred resolved to multiple values, the corresponding argument will be an array of those values. For example:

var d1 = $.Deferred();
var d2 = $.Deferred();
var d3 = $.Deferred();
 
$.when( d1, d2, d3 ).done(function ( v1, v2, v3 ) {
    console.log( v1 ); // v1 is undefined
    console.log( v2 ); // v2 is "abc"
    console.log( v3 ); // v3 is an array [ 1, 2, 3, 4, 5 ]
});
 
d1.resolve();
d2.resolve( "abc" );
d3.resolve( 1, 2, 3, 4, 5 );