前一篇文章中重點總結了一下then方法,它主要用來處理多個異步任務按順序執行,即前一個任務處理完了,再繼續下一個,以此類推;html
而這一章節jQuery.when方法也是處理多個異步任務,它把多個異步任務(Promise對象)合併爲一個Promise對象,這個合併後的Promise對象數組
究竟是如何來更新它的狀態,即什麼時候執行,拒絕?讓咱們繼續往下看吧!promise
jQuery回調、遞延對象總結篇索引:架構
jQuery回調、遞延對象總結(上篇)—— jQuery.Callbacks 併發
jQuery回調、遞延對象總結(中篇) —— 神奇的then方法 異步
jQuery回調、遞延對象總結(下篇) —— 解密jQuery.when方法函數
執行jQuery.when將會返回一個Promise對象,咱們稱做由when生成的Promise對象,若是給定的全部Promise對象均已執行,就當即執行this
由when方法產生的Promise對象,若是給定的Promise對象中有任意一個被拒絕,就當即拒絕由when生成的Promise對象,這樣作的意圖spa
好像就是爲了解決這樣一種需求:在指定的多個異步事件都完成了,而後才能幹本身想幹的事情設計
jQuery.extend({ // Deferred helper // 參數爲Promise對象,咱們稱做:給定的Promise對象 // when函數內部的deferred對象,咱們稱做:由when生成的Promise對象 when: function( subordinate /* , ..., subordinateN */ ) { var i = 0, resolveValues = core_slice.call( arguments ), length = resolveValues.length, // the count of uncompleted subordinates // 用來存儲給定的未執行(解決)的Promise對象的個數 remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, // the master Deferred. If resolveValues consist of only a single Deferred, just use that. // 咱們稱deferred爲when生成的Promise對象 deferred = remaining === 1 ? subordinate : jQuery.Deferred(), // Update function for both resolve and progress values updateFunc = function( i, contexts, values ) { return function( value ) { contexts[ i ] = this; values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value; // 若是給定的任意一個Promise對象未執行或拒絕,則通知由when生成的Promise對象爲pending狀態 // 注:contexts是由全部給定的Promise對象組成的數組, // values是由處理全部給定的Promise對象的回調的參數組成的數組 if( values === progressValues ) { deferred.notifyWith( contexts, values ); } // 若是給定的Promise對象已執行(解決),且當未執行的Promise對象個數爲0, // 即:給定的全部Promise對象都已執行(解決),則當即執行由when生成的Promise對象 // 注:contexts是由全部給定的Promise對象組成的數組, // values是由處理全部給定的Promise對象的回調的參數組成的數組(請看實例1) else if ( !( --remaining ) ) { deferred.resolveWith( contexts, values ); } }; }, progressValues, progressContexts, resolveContexts; // add listeners to Deferred subordinates; treat others as resolved if ( length > 1 ) { progressValues = new Array( length ); progressContexts = new Array( length ); // resolveValues = core_slice.call( arguments ) // 別忘了最上面的這行代碼 resolveContexts = new Array( length ); for ( ; i < length; i++ ) { // 若是給定when的參數是一個Promise對象,則通知由when生成的Promise對象,通知什麼,如何通知? // 若是給定的Promise對象已執行,則執行由when生成的Promise對象(要等到全部給定Promise對象所有執行) // 若是給定的任意一個Promise對象已拒絕,則拒絕由when生成的Promise對象 // 若是未執行或拒絕,默認是pending狀態 if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { resolveValues[ i ].promise() .done( updateFunc( i, resolveContexts, resolveValues ) ) .fail( deferred.reject ) .progress( updateFunc( i, progressContexts, progressValues ) ); } // 若是給定的不是一個Promise對象,那麼負責減一 else { --remaining; } } } // if we're not waiting on anything, resolve the master // 若是傳遞給when的參數都不是遞延對象,則執行由when生成的Promise對象 if ( !remaining ) { // resolveContexts爲一個空數組new Array( length ),resolveValues是由when參數組成的一個數組 deferred.resolveWith( resolveContexts, resolveValues ); } return deferred.promise(); } });
實例:關於執行由when生成的Promise對象的參數的問題
var promiseA = $.Deferred(); var promiseB = $.Deferred(); var doneFn = function(arg){ console.log(arg); }; promiseA.done(doneFn); promiseB.done(doneFn); promiseA.resolve('A'); // 'A' promiseB.resolve('B'); // 'B' var whenFn = function(arg1, arg2){ console.log(this[0] === promiseA.promise()); // true console.log(this[1] === promiseB.promise()); // true console.log('promise' + arg1 + ', promise' + arg2 + ' All done!'); }; var whenPromise = jQuery.when(promiseA, promiseB); whenPromise.done(whenFn); // true true 'promiseA, promiseB All done!'
遞延對象中的then方法做用於使多個異步任務按照順序執行,而jQuery.when方法做用於在多個併發的異步任務執行完畢後再幹本身感興趣的事情;
jQuery遞延對象是基於jQuery回調對象架構的,若是你想熟練掌握jQuery遞延對象,請先移步jQuery.Callbacks對象
PS: 若有描述錯誤,請幫忙指正,若是大家有不明白的地方也能夠發郵件給我,