jQueryソース分析-05非同期キューDeferred使用紹介
14854 ワード
5.非同期キューDeferred
5.1概要
非同期キューはチェーンオブジェクトであり、コールバック関数の管理と呼び出しを強化し、非同期タスクを処理します.
非同期キューには、初期化(unresolved)、成功(resolved)、失敗(rejected)の3つのステータスがあります.
どのコールバック関数を実行するかは、ステータスに依存します.
ステータスが成功(resolved)または失敗(rejected)になった後も、変わらないままです.
コールバック関数のバインドは、同期でも非同期でも、いつでもバインドできます.
(このセクションのバインド登録の増加は同じ意味です)
5.2重要な方法
まずjQueryを見てみましょうDeferred()でのキーメソッド
ぶんかつ
方法
説明
ふえる
deferred.done()
成功コールバック関数の追加
ステータスが正常(resolved)の場合、すぐに呼び出されます.
deferred.fail()
失敗コールバック関数の追加
ステータスが失敗(rejected)の場合は直ちに呼び出す
deferred.then()
成功コールバック関数と失敗コールバック関数をそれぞれのキューに追加
便利な方法で、2つのパラメータは配列またはnullです.
ステータスが成功(resolved)の場合、成功コールバック関数が直ちに呼び出されます.
ステータスが失敗(rejected)の場合、失敗コールバック関数をすぐに呼び出す
deferred.always()
コールバック関数を増加し、成功したキューと失敗したキューに追加
ステータスが決定された場合(成功または失敗にかかわらず)、コールバック関数が呼び出されます.
実行
deferred.resolve()
正常なコールバック関数キューの呼び出し
deferredを呼び出す.resolveWith()実装
deferred.resolveWith()
指定したコンテキストとパラメータを使用して正常なコールバック関数を実行
deferred.reject()
失敗したコールバック関数キューの呼び出し
deferredを呼び出す.rejectWith()実装
deferred.rejectWith()
指定したコンテキストとパラメータを使用して失敗したコールバック関数キューを実行
その他
deferred.isRejected()
ステータスが成功したかどうかを判断する(resolved)
deferred.isResolved()
ステータスが失敗かどうかを判断する(rejected)
deferred.pipe()
コールバック関数を呼び出すたびに、入力された成功フィルタ関数または失敗フィルタ関数が呼び出され、フィルタ関数の戻り値がコールバック関数のパラメータとして使用されます.
最終的に読み取り専用ビューを返します(promiseインプリメンテーションを呼び出します)
deferred.promise()
deferredの読み取り専用ビューを返します
次はjQuery.DeferredとjQuery.Deferredのソースコードの詳細な分析.
5.3 jQuery._Deferred
5.4 jQuery.Deferred
5.5 jQuery.when
5.6 Deferredアプリケーション
l jQuery.ajax()
n TODO
5.7学べるテクニック
l閉パッケージ
l null、undefinedによるReferenceErrorの回避に関する一般的なテクニック
args = args || [];
l動的配列を巡るテクニック
while( callbacks[ 0 ] ) {
callbacks.shift().apply( context, args );
}
l try/catch/finally実装エラー処理
構文
説明
try {
//tryStatements
} catch( exception ) {
//catchStatements
} finally {
//finallyStatements
}
tryStatements
必須オプション.
エラーが発生する可能性のある文.
exception
必須オプション.任意の変数名.
Exceptionの初期化値は、投げ出されたエラーの値です.
catchStatements
を選択します.
関連するtryStatementで発生したエラーを処理する文.
finallyStatements
を選択します.
他のすべてのプロシージャが発生した後に無条件に実行される文.
lチェーンオブジェクト:thisに戻ることでチェーン呼び出しを実現
方法
戻り値
done
this(deferred)
resolveWith
this(deferred)
resolve
this(deferred)
cancel
this(deferred)
lコード多重$.each
jQuery.each( {
done:[fnDone,[resolve],//doneは後文でdeferredを指す.done
fail: [ fnFail, "reject"]
}, function( handler, data ) {
//共通コード多重化
});
5.8後続
l DeferredのjQueryへの応用
l Deferredのカスタムアプリケーション
5.1概要
非同期キューはチェーンオブジェクトであり、コールバック関数の管理と呼び出しを強化し、非同期タスクを処理します.
非同期キューには、初期化(unresolved)、成功(resolved)、失敗(rejected)の3つのステータスがあります.
どのコールバック関数を実行するかは、ステータスに依存します.
ステータスが成功(resolved)または失敗(rejected)になった後も、変わらないままです.
コールバック関数のバインドは、同期でも非同期でも、いつでもバインドできます.
(このセクションのバインド登録の増加は同じ意味です)
5.2重要な方法
まずjQueryを見てみましょうDeferred()でのキーメソッド
ぶんかつ
方法
説明
ふえる
deferred.done()
成功コールバック関数の追加
ステータスが正常(resolved)の場合、すぐに呼び出されます.
deferred.fail()
失敗コールバック関数の追加
ステータスが失敗(rejected)の場合は直ちに呼び出す
deferred.then()
成功コールバック関数と失敗コールバック関数をそれぞれのキューに追加
便利な方法で、2つのパラメータは配列またはnullです.
ステータスが成功(resolved)の場合、成功コールバック関数が直ちに呼び出されます.
ステータスが失敗(rejected)の場合、失敗コールバック関数をすぐに呼び出す
deferred.always()
コールバック関数を増加し、成功したキューと失敗したキューに追加
ステータスが決定された場合(成功または失敗にかかわらず)、コールバック関数が呼び出されます.
実行
deferred.resolve()
正常なコールバック関数キューの呼び出し
deferredを呼び出す.resolveWith()実装
deferred.resolveWith()
指定したコンテキストとパラメータを使用して正常なコールバック関数を実行
deferred.reject()
失敗したコールバック関数キューの呼び出し
deferredを呼び出す.rejectWith()実装
deferred.rejectWith()
指定したコンテキストとパラメータを使用して失敗したコールバック関数キューを実行
その他
deferred.isRejected()
ステータスが成功したかどうかを判断する(resolved)
deferred.isResolved()
ステータスが失敗かどうかを判断する(rejected)
deferred.pipe()
コールバック関数を呼び出すたびに、入力された成功フィルタ関数または失敗フィルタ関数が呼び出され、フィルタ関数の戻り値がコールバック関数のパラメータとして使用されます.
最終的に読み取り専用ビューを返します(promiseインプリメンテーションを呼び出します)
deferred.promise()
deferredの読み取り専用ビューを返します
次はjQuery.DeferredとjQuery.Deferredのソースコードの詳細な分析.
5.3 jQuery._Deferred
// :
// http://api.jquery.com/category/deferred-object/
// Deferred http://www.cnblogs.com/fjzhou/archive/2011/05/30/jquery-source-3.html
// jQuery 1.5 deferred http://developer.51cto.com/art/201103/248638.htm
// Promise http://www.cnblogs.com/sanshi/archive/2011/03/11/1981789.html
// Promises/A http://wiki.commonjs.org/wiki/Promises/A
var // Promise methods
// , :resolveWith resolve rejectWith reject pipe when cancel
// resolve reject cancel
promiseMethods = "done fail isResolved isRejected promise then always pipe".split( " " ),
// Static reference to slice
// slice ,
sliceDeferred = [].slice;
_Deferred:
_Deferred: function() {
var // callbacks list
// ( , )
callbacks = [],
// stored [ context , args ]
// 、 , (fired )
// “ ” “ ” ;
// done , fired 0
fired,
// to avoid firing when already doing so
// ,
firing,
// flag to know if the deferred has been cancelled
// , done resolve resolveWith
cancelled,
// ( , )
// the deferred itself
deferred = {
// done( f1, f2, ...)
// , (resolved)
done: function() {
// ,
if ( !cancelled ) {
// :
// 1. , ;
// 2. ,
// : Java , 、 , JavaScript
var args = arguments, //
i, //
length, //
elem, //
type, // elem
_fired; // fired(fired )
// ( fired )
// _fired, fired 0
if ( fired ) {
_fired = fired;
fired = 0;
}
// arguments
for ( i = 0, length = args.length; i < length; i++ ) {
elem = args[ i ];
type = jQuery.type( elem );
// ,
if ( type === "array" ) {
// deferred, , deferred
deferred.done.apply( deferred, elem );
} else if ( type === "function" ) {
callbacks.push( elem );
}
}
// (_fired Deferred ),
// context args
if ( _fired ) {
deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] );
}
}
return this;
},
// resolve with given context and args
// ,
resolveWith: function( context, args ) {
// , :
// ,
if ( !cancelled && !fired && !firing ) {
// make sure args are available (#8421)
// args , null、undefined ReferenceError
args = args || [];
// firing 1
firing = 1;
try {
//
while( callbacks[ 0 ] ) {
// context, this
callbacks.shift().apply( context, args );
}
}
// JavaScript try/catch/finally
finally {
fired = [ context, args ];
firing = 0;
}
}
return this;
},
// resolve with this as context and given arguments
// Resolved
// , Resolved, isResolved firing、fired 。
//
resolve: function() {
deferred.resolveWith( this, arguments );
return this;
},
// Has this deferred been resolved?
// ( )?
// , /
// “ ” ,
isResolved: function() {
//
//
// ( fired /0)
return !!( firing || fired );
},
// Cancel
//
// ,
cancel: function() {
cancelled = 1;
callbacks = [];
return this;
}
};
return deferred;
}
5.4 jQuery.Deferred
// Full fledged deferred (two callbacks list)
// ( )
// : (unresolved), (resolved), (rejected)。
// 。
// (resolved) (rejected) , 。
Deferred: function( func ) {
// _Deferred , : 、 、 、
// , _Deferred
// failDeferred
var deferred = jQuery._Deferred(),
failDeferred = jQuery._Deferred(),
promise;
// Add errorDeferred methods, then and promise
jQuery.extend( deferred, {
//
// , null
// (resolved)
// (rejected)
then: function( doneCallbacks, failCallbacks ) {
// : done deferred, fail failDeferred.done, fail failDeferred
// :
// done deferred doneCallbacks
// fail failDeferred failCallbacks
// , failDeferred
deferred.done( doneCallbacks ).fail( failCallbacks );
// deferred
return this;
},
// callback , resolved rejected 。
// , ( ), deferred failDeferred
// ,
always: function() {
// done deferred,fail this
// done fail ? ! this deferred
// ? then ?
// fail fail failDeferred.done, failDeferred,failDeferred callbacks ,
// failDeferred.done deferred, failDeferred.done ,
// failDeferred.done this deferred, ,
// this, this
// ,always then
// , ( then ), :
// deferred.done( arguments ).fail( arguments );
// returnr this;
return deferred.done.apply( deferred, arguments ).fail.apply( this, arguments );
},
//
// (rejected)
fail: failDeferred.done,
//
// failDeferred.rejectWith()
rejectWith: failDeferred.resolveWith,
//
// failDeferred.resolve()
reject: failDeferred.resolve,
// (resolved)
isRejected: failDeferred.isResolved,
// ,
// ( promise )
// fnDone (resolved)
// fnFail (rejected)
// :
// 1. “ ”, ,
// 2. : pipe, fnDone fnFail
pipe: function( fnDone, fnFail ) {
return jQuery.Deferred(function( newDefer ) {
jQuery.each( {
done: [ fnDone, "resolve" ], // done deferred.done
fail: [ fnFail, "reject" ]
}, function( handler, data ) {
var fn = data[ 0 ],
action = data[ 1 ],
returned;
if ( jQuery.isFunction( fn ) ) {
deferred[ handler ](function() {
returned = fn.apply( this, arguments );
if ( returned && jQuery.isFunction( returned.promise ) ) {
returned.promise().then( newDefer.resolve, newDefer.reject );
} else {
newDefer[ action ]( returned );
}
});
} else {
deferred[ handler ]( newDefer[ action ] );
}
});
}).promise();
},
// Get a promise for this deferred
// If obj is provided, the promise aspect is added to the object
// Deferred , resolve reject, Deferred ,
// , 。
//
// $.ajax 1.5 XMLHttpRequest, XMLHttpRequest Deferred object。
// Deferred promise() , resolve reject, ajax 。
// ajax 。
promise: function( obj ) {
if ( obj == null ) {
// promise, promise
if ( promise ) {
return promise;
}
promise = obj = {};
}
var i = promiseMethods.length;
//
// :
// for( i = 0; i < len; i++ ) for( i = len-1; i >=0; i-- ) for( i = len; i--; )
// jQuery !
while( i-- ) {
obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ];
}
return obj;
}
});
// Make sure only one callback list will be used
// ,
// ,
// , , ;
// 、 ,
// deferred failDeferred canceled , , 、
deferred.done( failDeferred.cancel ).fail( deferred.cancel );
// Unexpose cancel
// cancel ,
delete deferred.cancel;
// Call given func if any
// func
if ( func ) {
func.call( deferred, deferred );
}
return deferred;
}
5.5 jQuery.when
// Deferred helper
//
// firstParam: Deferred JavaScript
when: function( firstParam ) {
var args = arguments,
i = 0,
length = args.length,
count = length,
// arguments.length 1, firstParam Deferred, deferred=firstParam
// Deferred ( arguments.length 0 1, Deferred )
// jQuery.isFunction( firstParam.promise ) Deferred
deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ?
firstParam :
jQuery.Deferred();
// (resolve)
function resolveFunc( i ) {
return function( value ) {
// , (arguments slice , )
args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
if ( !( --count ) ) {
// Strange bug in FF4:
// Values changed onto the arguments object sometimes end up as undefined values
// outside the $.when method. Cloning the object into a fresh array solves the issue
// , Deferred
deferred.resolveWith( deferred, sliceDeferred.call( args, 0 ) );
}
};
}
//
if ( length > 1 ) {
for( ; i < length; i++ ) {
// Deferred , .promise().then(),
if ( args[ i ] && jQuery.isFunction( args[ i ].promise ) ) {
//
args[ i ].promise().then( resolveFunc(i), deferred.reject );
} else {
// , Deferred , JavaScript
--count;
}
}
// 0 , Deferred
// , Deferred
if ( !count ) {
deferred.resolveWith( deferred, args );
}
// deferred !== firstParam, deferred Deferred
// length == 0
} else if ( deferred !== firstParam ) {
// , Deferred
deferred.resolveWith( deferred, length ? [ firstParam ] : [] );
}
// Deferred Deferred
return deferred.promise();
}
5.6 Deferredアプリケーション
l jQuery.ajax()
n TODO
5.7学べるテクニック
l閉パッケージ
function a(){
var guid = 1;
return function(){
return guid++;
}
}
var defer = a();
console.info( defer() ); // 1
console.info( defer() ); // 2
console.info( defer() ); // 3
console.info( defer() ); // 4
l null、undefinedによるReferenceErrorの回避に関する一般的なテクニック
args = args || [];
l動的配列を巡るテクニック
while( callbacks[ 0 ] ) {
callbacks.shift().apply( context, args );
}
l try/catch/finally実装エラー処理
構文
説明
try {
//tryStatements
} catch( exception ) {
//catchStatements
} finally {
//finallyStatements
}
tryStatements
必須オプション.
エラーが発生する可能性のある文.
exception
必須オプション.任意の変数名.
Exceptionの初期化値は、投げ出されたエラーの値です.
catchStatements
を選択します.
関連するtryStatementで発生したエラーを処理する文.
finallyStatements
を選択します.
他のすべてのプロシージャが発生した後に無条件に実行される文.
lチェーンオブジェクト:thisに戻ることでチェーン呼び出しを実現
方法
戻り値
done
this(deferred)
resolveWith
this(deferred)
resolve
this(deferred)
cancel
this(deferred)
lコード多重$.each
jQuery.each( {
done:[fnDone,[resolve],//doneは後文でdeferredを指す.done
fail: [ fnFail, "reject"]
}, function( handler, data ) {
//共通コード多重化
});
5.8後続
l DeferredのjQueryへの応用
l Deferredのカスタムアプリケーション