Deferred
最近在看deferred,有一些疑問,于是研究了一下,現(xiàn)在理解程度也就是70%-80%
這個(gè)方法基于callbacks,所以說,如果要看原理,最好先看一下callbacks的源碼。下面我貼上源碼,進(jìn)行分析一下,會(huì)加上自己的理解,我主要困惑在when和then方法上,會(huì)重點(diǎn)說一下,這里說一下基本的源碼分析網(wǎng)上有很多,大家可以搜一下,這里鏈接一個(gè)when和then方法的例子地址:
http://www.ruanyifeng.com/blog/2011/08/a_detailed_explanation_of_jquery_deferred_object.html
http://www.css88.com/jqapi-1.9/deferred.then/
ok,進(jìn)入源碼jQuery.extend({
Deferred: function( func ) {//開始定義變量var tuples = [// action, add listener, listener list, final state[ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],[ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],[ "notify", "progress", jQuery.Callbacks("memory") ]],state = "pending",promise = {
//返回狀態(tài)state: function() {return state;},
//無論成功與否都調(diào)用里面的參數(shù)(一般參數(shù)都是函數(shù))always: function() {deferred.done( arguments ).fail( arguments );return this;},
//分別對應(yīng)完成后運(yùn)行的函數(shù),失敗后運(yùn)行的函數(shù),正在運(yùn)行過程中運(yùn)行的函數(shù)then: function( /* fnDone, fnFail, fnProgress */ ) {
//保存參數(shù)var fns = arguments;
//直接返回一個(gè)deferred的方法,即直接返回一個(gè)deferred對象,
//這里的newDefer就是我們的return jQuery.Deferred(。。)的返回的新的deferred對象,源碼Deferred方法的參數(shù)如果是函數(shù)的話
//會(huì)立即執(zhí)行,源碼如下:if ( func ) {func.call( deferred, deferred );},此時(shí)會(huì)把deferred作為參數(shù)傳遞進(jìn)去
return jQuery.Deferred(function( newDefer ) { //循環(huán)遍歷tuples,分別對不同狀態(tài)注冊函數(shù) jQuery.each( tuples, function( i, tuple ) //取出“動(dòng)作”:resolve(解決)、reject(拒絕)、notify(通知) var action = tuple[ 0 ],
//取出對應(yīng)回調(diào)函數(shù),這里的i用的比較巧妙,如果fns[i]不存在返回false,否則返回函數(shù) fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; // deferred[ done | fail | progress ] for forwarding actions to newDefer
//這里dererred的各個(gè)狀態(tài)的add方法添加了newDefer的fire方法,以后deferred調(diào)用fire的話,這個(gè)新的newDefer也同樣fire
deferred[ tuple[1] ](function() {
//這里注意一下,這里相當(dāng)于if(fn){returned = fn.apply(this,arguments)};
//這時(shí)候的returned相當(dāng)于函數(shù)fn執(zhí)行完畢之后的結(jié)果,后面舉例子,就會(huì)看到效果了,這個(gè)this和arguments就是在fire的時(shí)候傳遞進(jìn)來的,源碼如下(for each中體現(xiàn)的):
//deferred[ tuple[0] ] = function() {deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );return this;}; var returned = fn && fn.apply( this, arguments );
//如果返回的結(jié)果是一個(gè)deferred對象,則把newDefer跟這個(gè)deferred對象關(guān)聯(lián),保證一個(gè)fire引起另外一個(gè)fire if ( returned && jQuery.isFunction( returned.promise ) ) { returned.promise() .done( newDefer.resolve ) .fail( newDefer.reject ) .progress( newDefer.notify ); } else {
//直接調(diào)用各個(gè)狀態(tài)的fireWith方法,如果fn存在就直接把returned放入 newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments ); } }); }); fns = null; }).promise(); }, // Get a promise for this deferred// If obj is provided, the promise aspect is added to the object
//如果有參數(shù)就通過promise擴(kuò)展obj,即把promise的屬性都復(fù)制到到obj中,如果obj不存在則直接返回promise
//promise跟deferred區(qū)別在于deferred有很多可以改變對象的方法(rejectWith、resolveWith等),promise沒有promise: function( obj ) { return obj != null ? jQuery.extend( obj, promise ) : promise; } }, deferred = {}; // Keep pipe for back-compatpromise.pipe = promise.then; // Add list-specific methods
//這里主要就是把tuples的各個(gè)屬性進(jìn)行一一解析賦值到defferred中,
jQuery.each( tuples, function( i, tuple ) {
//list就是各個(gè)狀態(tài)的callbacks的list,stateString是狀態(tài) var list = tuple[ 2 ], stateString = tuple[ 3 ]; // promise[ done | fail | progress ] = list.add
//把各個(gè)狀態(tài)的done、fail、progress方法直接掛到callbacks的add上面
promise[ tuple[1] ] = list.add; // Handle state
//如果狀態(tài)存在,也就是tuples的前兩組
if ( stateString ) {
//done和fail狀態(tài),分別添加三個(gè)函數(shù)(改變自己的state,把另外一個(gè)狀態(tài)設(shè)置為不可用,把第三個(gè)狀態(tài)鎖死),這樣為了保證只有一個(gè)狀態(tài)執(zhí)行例如:done的時(shí)候fail和process就不能執(zhí)行了 list.add(function() { // state = [ resolved | rejected ]state = stateString; // [ reject_list | resolve_list ].disable; progress_list.lock
//這個(gè)學(xué)一下,i^1,這個(gè)是異或運(yùn)算符,效率高,特點(diǎn):只有一個(gè)是1的時(shí)候才等于1
}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); } // deferred[ resolve | reject | notify ]
//定義fireWith方法,所謂的修改方法
deferred[ tuple[0] ] = function() { deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments ); return this; };
//把fireWith跟callbacks的fireWith進(jìn)行綁定 deferred[ tuple[0] + "With" ] = list.fireWith; }); // Make the deferred a promise
//擴(kuò)展deferred,把promise的屬性擴(kuò)展到defrred中
promise.promise( deferred ); // Call given func if any
//剛才上面提到的,Deferred()的參數(shù)如果是函數(shù),則立即調(diào)用,參數(shù)就是將要返回的deferred對象
if ( func ) { func.call( deferred, deferred ); } // All done!return deferred; }, // Deferred helper
//這個(gè)方法是jq的擴(kuò)展,他的作用就是把放入其中的N個(gè)異步方法做一個(gè)計(jì)數(shù),知道最后一個(gè)方法完成之后,才執(zhí)行when后面的方法
when: function( subordinate /* , ..., subordinateN */ ) {
//定義變量,resolveValues把參數(shù)轉(zhuǎn)化成數(shù)組 var i = 0, resolveValues = core_slice.call( arguments ), length = resolveValues.length, // the count of uncompleted subordinates
//remaining存放參數(shù)長度,也就是通過它來通知when是否所有的異步方法都執(zhí)行完了
remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
//如果remaining等于1,則肯定是deferred,如果參數(shù)大于1,則新定義一個(gè)deferred
deferred = remaining === 1 ? subordinate : jQuery.Deferred(), // Update function for both resolve and progress values
//更新remaining長度,以及判斷是否是最后一個(gè)異步,如果是最后一個(gè),則調(diào)用deferred的fire方法,從而觸發(fā)when()后面的方法調(diào)用
updateFunc = function( i, contexts, values ) { return function( value ) { contexts[ i ] = this; values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value; if( values === progressValues ) { deferred.notifyWith( contexts, values ); } else if ( !( --remaining ) ) {
//計(jì)數(shù)為0的時(shí)候,調(diào)用deferred的fire方法 deferred.resolveWith( contexts, values ); } }; }, progressValues, progressContexts, resolveContexts; // add listeners to Deferred subordinates; treat others as resolvedif ( length > 1 ) { progressValues = new Array( length ); progressContexts = new Array( length ); resolveContexts = new Array( length ); for ( ; i < length; i++ ) {
//判斷傳進(jìn)來的參數(shù)是否是deferred,不是則直接計(jì)數(shù)減一,是的話,調(diào)用deferred的promise()方法返回promise對象,然后添加updateFunc函數(shù),
//當(dāng)參數(shù)中的函數(shù)fire的時(shí)候,就調(diào)用updateFunc函數(shù),計(jì)數(shù)減一,直到為0
//整體思路,就是定義一個(gè)全局變量保存總共的參數(shù)個(gè)數(shù),然后寫一個(gè)公共函數(shù),分配到各個(gè)參數(shù)函數(shù)中,每次函數(shù)執(zhí)行完畢,就執(zhí)行公共函數(shù)去操作公共變量減一,
if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { resolveValues[ i ].promise() .done( updateFunc( i, resolveContexts, resolveValues ) ) .fail( deferred.reject ) .progress( updateFunc( i, progressContexts, progressValues ) ); } else { --remaining; } } } // if we're not waiting on anything, resolve the masterif ( !remaining ) { deferred.resolveWith( resolveContexts, resolveValues ); } return deferred.promise(); } });
?when函數(shù)例子:
var dtd = $.Deferred(); // 新建一個(gè)deferred對象
var wait = function(dtd){
var tasks = function(){
alert("執(zhí)行完畢!");
dtd.resolve(); // 改變deferred對象的執(zhí)行狀態(tài)
};
setTimeout(tasks,5000);
return dtd;
};
$.when(wait(dtd))
.done(function(){ alert("哈哈,成功了!"); })
.fail(function(){ alert("出錯(cuò)啦!"); });
?
then函數(shù)例子:
var filterResolve = function() {
var defer = $.Deferred(),
filtered = defer.then(function( value ) {
return value * 2;
});
defer.resolve( 5 );
filtered.done(function( value ) {
alert(value);//10
});
};
filterResolve();
說說這個(gè)then的執(zhí)行邏輯,在源代碼中也提到過
?1)定義一個(gè)deferred對象defer
?2)defer的then方法執(zhí)行過程,可以這么理解
a)var filtered = $.Deferred(),fn =?function(value){return value*2;}
b)defer.add(filtered.resolve(fn()));
當(dāng)調(diào)用defer的add的時(shí)候,相當(dāng)于filtered的fire方法,而fire的參數(shù)是fn()函數(shù)的返回值,
當(dāng)filtered再次done(add方法)的時(shí)候,直接執(zhí)行上次的fire方法,而參數(shù)也是上一個(gè)的參數(shù),參見callbacks的 once memory特性
?
轉(zhuǎn)載于:https://www.cnblogs.com/aishangyizhihu/p/4232142.html
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
- 上一篇: win7 64 下安装ubuntu14.
- 下一篇: [数据结构]二叉树