jQueryソースコード解析-05 非同期キュー ディファードユース入門_jquery

WBOY
リリース: 2016-05-16 17:59:42
オリジナル
1120 人が閲覧しました

5. 非同期キュー Deferred
5.1 概要
非同期キューは、コールバック関数の管理と呼び出しを強化する連鎖オブジェクトであり、非同期タスクの処理に使用されます。
非同期キューには、初期化 (未解決)、成功 (解決)、および失敗 (拒否) の 3 つの状態があります。
どのコールバック関数が実行されるかは状態によって異なります。
ステータスが解決済みまたは拒否に変更された後も、ステータスは変更されません。
コールバック関数のバインドは同期または非同期にすることができます。つまり、いつでもバインドできます。
(このセクションのバインディング登録の追加も同じ意味です)
5.2 主要なメソッド
まずは jQuery の主要なメソッドを見てみましょう。
分類
メソッド
説明

deferred.done() を追加
成功コールバック関数を追加
ステータスが成功 (解決) になったらすぐに呼び出します
deferred.fail()
失敗コールバック関数を追加
ステータス 拒否された (拒否された) 場合はすぐに
deferred.then() を呼び出します
成功コールバック関数と失敗コールバック関数をそれぞれのキューに追加します
コンビニエンス メソッド、2 つのパラメータは配列または null にすることができます
status ステータスが成功(解決)の場合は、すぐに成功のコールバック関数を呼び出します。
ステータスが失敗(拒否)の場合は、失敗のコールバック関数をすぐに呼び出します。
deferred.always()
コールバック関数を追加し、成功キューと失敗キューに同時に入れます
成功・失敗に関係なくステータスが決まったらすぐにコールバック関数を呼び出します

deferred.resolve()を実行します
成功を呼び出しますコールバック関数 queue
deferred.resolveWith()
deferred.resolveWith()
指定されたコンテキストとパラメータを使用して成功コールバック関数を実行します
deferred.reject()
失敗を呼び出しますcallback function queue
deferred.rejectWith() を呼び出して
deferred を実装します。rejectWith()
指定されたコンテキストとパラメーターを使用して失敗したコールバック関数キューを実行します
Others
deferred.isRejected()
ステータスが成功 (解決済み) かどうかを判断します
deferred.isResolved()
ステータスが失敗 (拒否) であるかどうかを判断します
deferred.pipe()
受信した成功フィルター関数または失敗を呼び出しますコールバック関数を呼び出すたびにフィルター関数を呼び出し、フィルター関数の戻り値をコールバック関数として使用します。パラメーター
は最終的に読み取り専用ビューを返します (promise を呼び出すことで実装されます)
deferred.promise()
は deferred の読み取り専用ビューを返します
次に、jQuery._Deferred と jQuery.Deferred のソース コードを詳細に分析します。


5.3 jQuery._Deferred

コードをコピー コードは次のとおりです。

ローカル変数
// 参考文献:
// 公式 Web サイトのドキュメント http://api.jquery.com/category/deferred-object/
// 遅延メカニズム http:// www.cnblogs.com/fjzhou/archive/2011/05/30/jquery-source-3.html
// jQuery 1.5 での遅延オブジェクトの使用 http://developer.51cto.com/art/201103/248638 。 htm
// 虫眼鏡で約束を見てください http://www.cnblogs.com/sanshi/archive/2011/03/11/1981789.html
// 約束/A http://wiki. commonjs .org/wiki/Promises/A
var // Promise メソッド
// 次のメソッドがないことに注意してください:solveWithsolvejectWith キャンセル時の拒否パイプ
//resolveject を呼び出すことは許可されていません
PromiseMethods = "done failed isResolved isRejected Promise then always Pipe".split( " " ),
// スライスへの静的参照
// スライス メソッドへの静的参照、レイにチキンを借用Egg
sliceDeferred = [].slice;
_Deferred:
_Deferred: function() {
var // コールバック リスト
// コールバック関数の配列 (概念を避けるため、ここではキューとして変換されません)混乱)
callbacks = [],
// storage [ context, args ]
// コンテキストとパラメータを保存し、実行が完了したかどうかも識別できます (fired は空ではないことを意味します)完了しました)
// ここでの「完了」は、コールバック関数配列内のすべての「既存の」関数が実行されたことを意味します。
// ただし、done を再度呼び出してコールバック関数を追加することもできます。追加、起動は 0 にリセットされます
fired,
// すでに実行中の場合は起動を避けるため
// トリガーがすでに実行されている場合は、再度起動しないようにします
fired,
/ / 遅延がキャンセルされたかどうかを知るためのフラグ
// 非同期キューがキャンセルされたかどうかを識別します。 キャンセル、完了の呼び出しは、キャンセル後は無視されます。
canceled,
// 非同期キューの定義 (これが実際の所有者であり、上記のローカル変数はクロージャを通じて参照されます)
// 遅延自体
deferred = {
// done( f1, f2, ...)
// 追加成功コールバック関数。ステータスが成功 (解決) になったときにすぐに呼び出されます。
done: function() {
// キャンセルされた場合は、この呼び出しを無視します。
if ( !canceled ) {
// コード ブロックの先頭で後続のコードで使用されるローカル変数を定義する利点:
// 1. 宣言変数、コードの可読性の向上
// 2. 共有変数、パフォーマンスの向上
/ / 注: 私は長年 Java を書いてきた経験から、最初にグローバル変数を定義し、使用するときに一時変数を定義する習慣を身につけてきました。
var args = argument, / とは少し違うようです。 / コールバック関数の配列
i, // トラバース変数
length, // コールバック関数の配列の長さ
elem, // 単一のコールバック関数
type, // elem の型
_fired; fired の一時的なバックアップに使用されます (コンテキストとパラメータは fired に保存されます)
// 実行が完了した場合 (つまり、コンテキストとパラメータは fired に保持されます)
// コンテキストとパラメータをバックアップします
if ( fired ) {
_fired = fired;
fired = 0;
}
// コールバック関数配列
に引数関数を追加します( i = 0, length = args.length; i < length; i ) {
elem = args[ i ];
type = jQuery.type( elem );配列、再帰的に呼び出します
if ( type === "array" ) {
// コンテキストを遅延として指定するように強制します。デフォルトのコンテキストは次のとおりであるため、ここでコンテキストを指定する必要はないと個人的に思います。 deferred
deferred.done.apply( deferred, elem );
} else if ( type === "function" ) {
callbacks.push( elem );
}
// 実行されている場合 (_fired は Deferred のステータスが決定されていることを示します)、新しく追加された関数をすぐに実行します
// 以前に指定したコンテキスト context とパラメーター引数を使用します
if ( _fired ) {
deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] );
}
}
return this;
},
// 指定されたコンテキストと引数で解決します
// 指定されたコンテキストとパラメータを使用して実行します。
resolveWith: function( context, args ) {
// 次の条件がすべて満たされた場合にのみ実行されます: キャンセルなし、実行なし、実行完了なし
// キャンセル、完了、あるいは実行中の場合、この呼び出しは無視されます。
if ( !canceled && !fired && !firing ) {
// 引数が利用可能であることを確認してください (#8421)
// args が利用可能であることを確認します。これは、null および未定義によって引き起こされる ReferenceError を回避するための一般的な手法です。
args = args || []
// 実行中に起動を 1 に変更します。
firing = 1 ;
try {
// 動的配列を走査するためのヒント
while( callbacks[ 0 ] ) {
// ここでは、この
callbacks.shift( ではなく、指定されたコンテキストが使用されることに注意してください) ).apply( context, args );
}
}
// JavaScript は try/catch/finally をサポートします
finally {
fired = [ context, args ]; 0;
}
}
return this
},
// これをコンテキストと指定された引数で解決します
// ステータスを解決済みに設定します
// isResolved を呼び出して Resolved を取得して発火と発火のステータスを判断するため、設定の理解は正確ではありません。
//
resolve: function() {
deferred.resolveWith( this, argument );
return this;
// これは延期されています
// 実行されましたか (または解決されましたか)?
// 実行中または実行後に、実行/解決されたとみなされます
// 実行中に実行されたともみなされるため、「すでに」は不正確である可能性があります
isResolved: function( ) {
// 実行中
// または
// 終了しました (つまり、fired は空ではありません/0)
return !!( fired || fired );
// キャンセル
// 非同期キューをキャンセルします
// フラグ ビットを設定し、関数キューをクリアします
cancel: function() {
canceled = 1;
callbacks = [];
これを返します;
}
}
返却遅延;


5.4 jQuery.Deferred


コードをコピーします コードは次のとおりです:

// 本格的な遅延 (2 つのコールバック リスト)
// 完全な非同期キューを作成します (2 つのコールバック関数配列を含む)
// 非同期キューには 3 つの状態があります: 初期化 (未解決) 、成功 (解決)、失敗 (拒否)。
// どのコールバック関数が実行されるかは状態によって異なります。
// ステータスが解決済みまたは拒否に変更された後も、ステータスは変更されません。
Deferred: function( func ) {
// _Deferred には成功または失敗のステータスがありません。初期化、実行、実行完了、キャンセルの 4 つの状態があります。
// コードの再利用のために、最初に _Deferred を実装しました。
// クロージャを通じて参照されるfailDeferred
var deferred = jQuery._Deferred(),
failDeferred = jQuery._Deferred(),
promise
// errorDeferredメソッドを追加し、次にpromise
jQuery.extend( deferred, {
// 成功コールバック関数と失敗コールバック関数をそれぞれのキューに追加します
// 便利なメソッド。2 つのパラメータは配列または null にすることができます
// をすぐに呼び出しますステータスが成功 (解決) の場合は成功コールバック関数
// ステータスが失敗 (拒否) の場合は失敗コールバック関数をすぐに呼び出します。
then: function( donedCallbacks, failedCallbacks ) {
/ /ここでコンテキスト スイッチを指定します。done は deferred を返しますが、fail が実行されると、コンテキストはfailDeferred に変わります。
// 簡単に言うと、
// 呼び出し時に deferred にコールバックを追加します。 done Function donedCallbacks
// 呼び出し時にコールバック関数をfailDeferredに追加しますfailCallbacks
// したがって、この式の行が実行された後、failDeferred
deferred.done( doneCallbacks ).fail(failCallbacks ); 🎜>// 強制復帰遅延
return this;
},
// 解決されるか拒否されるかに関係なく呼び出されるコールバック関数を登録します。
// 実際には、渡された関数 (配列) は deferred とfailDeferred に同時に追加されます
// 想像していたように別の関数配列には格納されません
always: function( ) {
// 完了のコンテキストは遅延に設定され、失敗のコンテキストはこの
// 完了と失敗のコンテキストは矛盾していますか?一貫性のある!ここでは、これは deferred
// に等しいですが、このように設定されたコンテキストをどのように解釈すればよいでしょうか?当時の実装とどう違うのですか?
// 失敗は失敗を指し、failDeferred.done に失敗します。デフォルトのコンテキストは、failDeferred です。failDeferred のコールバック関数配列のコールバックは、クロージャを介して参照されます。
// これを、failDeferred.done の最後にある deferred に置き換えてチェーン呼び出しを実装します。
// つまり、このコンテキストは途中で失われません。
// 文法的には、always によって達成される効果は then によって達成される効果と一致します。
// したがって、これはコード行は 2 行に書き換えることができます ( then の実装と同様)。
// deferred.done( argument ).fail( argument );
// returnr this; >return deferred.done.apply( deferred, argument ).fail. apply( this, argument );
},
// 失敗コールバック関数を追加
// ステータスが失敗した場合にすぐに呼び出されます (拒否されました) )
fail:failDeferred.done,
// 指定されたコンテキストとパラメーターを使用して、失敗コールバック関数を実行します queue
// failedDeferred.rejectWith() を呼び出すことで
rejectWith:failDeferred.resolveWith,
// 失敗コールバック関数キューが呼び出されます
//failDeferred .resolve() を呼び出すことで、
reject:failDeferred.resolve,
// ステータスが成功 (解決済み) かどうかを判断します
isRejected :failDeferred.isResolved,
// 渡されたコールバック関数を毎回呼び出します 成功フィルター関数または失敗フィルター関数を入力し、フィルター関数の戻り値をコールバック関数のパラメーターとして使用します
// 最後に return読み取り専用ビュー (Promise を呼び出して実装する)
// fnDone が成功のステータスにあるかどうか (解決されたときに呼び出されます)
// fnFail はステータスが拒否された (拒否された) ときに呼び出されます
/ / その​​他の説明について:
// 1. 一部の記事では「パイプライン機構」と訳されていますが、文字通りの意味は理解できないため、少なくとも不正確です
// 2. 誤った理解: いわゆるパイプは、受信した 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[ハンドラー ](function() {
returned = fn.apply( this, argument );
if (returned && jQuery .isFunction(returned.promise ) ) {
returned.promise().then( newDefer .resolve, newDefer.reject );
} else {
newDefer[ アクション ]( 返された );
} else {
deferred[ ハンドラー ]( newDefer [ action ] );
}
});
}).promise();
} ,
// obj が提供されている場合、promise アスペクトがオブジェクトに追加されます。
// 返されるのは、resolve と拒否のない不完全な Deferred インターフェイスです。つまり、Deferred オブジェクトの状態は変更できません。
// これは、外部関数が早期にコールバック関数をトリガーするのを防ぐため、読み取り専用ビューと見なすことができます。
//
// たとえば、$.ajax はバージョン 1.5 以降、XMLHttpRequest を返さなくなりましたが、XMLHttpRequest および Deferred オブジェクト インターフェイスをカプセル化したオブジェクトを返します。
// Deferred 部分は、promise() によって取得されます。これにより、外部関数が release および拒否を呼び出すことがなくなり、ajax が完了する前にコールバック関数がトリガーされることがなくなります。
// これら 2 つの関数の呼び出し権限を内部的に ajax に予約します。
promise: function( obj ) {
if ( obj == null ) {
// Promise は実際には 1 回だけ実行され、最初の実行結果は 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
}
}); 🎜>// コールバック リストが 1 つだけ使用されることを確認してください
// 成功したキューの実行が完了した後、失敗したキューのキャンセル メソッドが実行されます
// 失敗したキューの実行が完了した後、成功したキューはcancel メソッドが実行されます
// 関数キューが 1 つだけ実行されることを確認します。つまり、実行成功キューまたは実行失敗キューのいずれかです。
// つまり、ステータスは成功または実行のいずれかのみです。失敗、クロスコールなし
// deferred およびfailDeferredのcancel属性はクロージャを通じてのみ参照できるため、状態とコンテキストの混同を心配する必要はありません
deferred.done(failDeferred.cancel).fail( deferred.cancel );
// unexpose cancel
// キャンセル インターフェイスを非表示にします。つまり、成功した関数キューを外部からキャンセルできません。
deferred.cancel
// 指定された呼び出しfunc if any
// 受信 func 関数を実行します
if ( func ) {
func.call( deferred, deferred );
}
return deferred;

5.5 jQuery.when



コードをコピー
コードは次のとおりです: // 遅延ヘルパー // 非同期キュー ツール関数// firstParam: 1 つまたは複数の遅延オブジェクトまたは JavaScript の通常のオブジェクト
when: function( firstParam ) {
var args = argument,
i = 0,
length = args.length,
count = length,
// argument.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()
// 成功した (解決する) コールバック関数を構築します
functionsolveFunc( i ) {
return function( value ) {
// 渡されたパラメーターが 1 より大きい場合、受け取ったパラメーターを実数の配列に変換します (引数にはスライス メソッドがないため、借用します)卵を産む鶏)
args[ i ] = argument.length > sliceDeferred.call( argument, 0 ) : value; / FF4 の奇妙なバグ:
// 引数オブジェクトに変更された値が、$.when メソッドの外で未定義の値になる場合があります。オブジェクトを新しい配列にクローンすると、問題が解決されます。 🎜>// コールバック関数キューが正常に実行され、コンテキストは
deferred.resolveWith( deferred, slideDeferred.call( args, 0 ) ) );
に渡された最初の Deferred オブジェクトに強制されます。 🎜>}
// パラメータが複数ある場合
if ( length > 1 ) {
for( ; i // 単純に、 Deferred オブジェクトの場合、 .promise().then() を呼び出します。それ以外の場合は、
if ( args[ i ] && jQuery.isFunction( args[ i ].promise ) ) {
// 成功コールバックを追加します。関数と失敗コールバック関数をそれぞれのキューに送信します
args[ i ].promise().then(solveFunc(i), deferred.reject );
} else {
// であることを示すカウンターこれは Deferred オブジェクトではなく、通常の JavaScript オブジェクトであることがわかりました。
--count;
}
}
// カウンタが 0 の場合、渡されたパラメータがどれも存在しないことを意味します。 Deferred オブジェクト
// 実行成功のコールバック関数のキュー。コンテキストは、
if ( !count ) {
deferred.resolveWith( deferred, args ); で渡される最初の Deferred オブジェクトになります。
// deferred !== firstParam、つまり deferred は新しく作成された Deferred オブジェクトです
// つまり、length == 0
} else if ( deferred !== firstParam ) {
// 正常に実行された場合のコールバック関数のキュー。コンテキストは新しく作成された Deferred オブジェクトに強制されます。
deferred.resolveWith( deferred, length ? [ firstParam ] : [] );
// 最初のオブジェクトを返します。渡された Deferred、または新しく作成された Deferred オブジェクトの読み取り専用ビュー
return deferred.promise();
}



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() ); // 3 console.info( defer() ); // 4
l null および未定義による ReferenceError を回避するための一般的な手法
args = args || [];
l 動的配列を走査する手法
while( callbacks[ 0 ] ) {
callbacks。 shift ().apply( context, args );
}
l try/catch/finally でエラー処理を実装します
構文
説明
try {
// tryStatements
} catch (例外) {
// catchStatements
}finally {
//finallyStatements
}
tryStatements
必須。
間違った記述の可能性があります。
例外
必須。任意の変数名。
例外の初期化値は、スローされたエラーの値です。
catchStatements
オプション。
関連する tryStatement で発生したエラーを処理するステートメント。
finallyStatements
オプション。
他のすべてのプロセスが発生した後に無条件に実行されるステートメント。
l 連鎖オブジェクト: this を返すことで連鎖呼び出しを実装します。
メソッド
戻り値
done
this (つまり、遅延)
resolveWith
this (つまり、遅延)
resolve
これ (つまり、延期)
キャンセル
これ (つまり、延期)
l コードの再利用 $.each
jQuery.each( {
done: [ fnDone, "resolve " ], // Done は記事の後半で deferred.done を指します
fail: [ fnFail, "reject" ]
}, function( handler, data ) {
// パブリック コードの再利用
}) ;
5.8 フォローアップ
l jQuery での Deferred のアプリケーション
l Deferred のカスタム アプリケーション
関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート