公式のjQuery.Callbacksドキュメントでは、多目的オブジェクトとして説明しています。これは、コールバック関数のリスト(コールバックは単にコールバックと呼ばれます)およびこのリストを管理するための強力なツールです。
このオブジェクトがまだ開発段階にあるときの機能を調べましたが、最初はリリースバージョンに残っていたよりも少し多くの可能性があったと言わなければなりません。 たとえば、現在、各
fire()
呼び出しに対して1つのコールバックのキューを作成する方法はありません。 どうやら、jQueryチームはコードを少し短くすることを決定し、ライブラリの重みを節約するために「不要な/あまり使用されない」機能を削除しました。 これは、コールバックの歴史への小さな余談ですが、以下では、現在利用可能な機能のみを説明し、最終的には、このオブジェクトに小さな可能な改善を記述します。
予定
この新しいjQuery.Callbacksオブジェクトの詳細な調査を開始する前に、このオブジェクトが必要な理由について詳しく説明します。 多くの場合、JavaScriptコードはコールバックを使用します。たとえば、アクションの完了後にイベントが発生したときに呼び出される関数です。最も顕著な例はAJAXリクエストです。 同時に、多くの場合、1つの関数ではなく、一度に複数の関数を呼び出す必要があります(何個、2、3、2ダース、またはまったくないかは事前にはわかりません)-これはよく知られたシンプルな「オブザーバー」パターンです。 そして、そのような場合には、問題のjQuery.Callbacksオブジェクトが役立ちます。 jQuery自体では、このオブジェクトはjQuery.DeferredおよびjQuery.ajax内で使用されます(バージョン1.7以降)。 また、jQueryの作成者は、このオブジェクトを公開して文書化し、他の開発者が独自のコンポーネントを実装するときに使用できるようにしました。
コンストラクター:jQuery.Callbacks(フラグ)
コンストラクターを呼び出すと、コールバックオブジェクトが作成されます。このオブジェクトには、コールバックリストを管理するためのいくつかのメソッドがあります。
flags
パラメーターはオプションであり、オブジェクトの操作パラメーターを設定できます;以下のパラメーターの可能な値を検討します。
var callbacks = $.Callbacks();
作成された
callbacks
オブジェクトに、オブジェクトの
callbacks
を使用して、
callbacks
関数をリストに追加、削除、呼び出し、再度呼び出し(オブジェクトの作成時に禁止されていない場合)、オブジェクトの状態(既に呼び出しがあるかどうか)を確認できます。
add()
、
remove()
、
fire()
など。コールバックは、リストに追加された順序で実行されます。
これは、クラスインスタンスの「実際の」コンストラクタではないため、呼び出すときに
new
演算子を使用する必要はありません(無意味です)。
このため、JSの標準的な方法では、オブジェクトがコールバックのインスタンスであるかどうかを確認することはできません。
if (obj instanceof $.Callbacks) { obj.add(fn); }
ifの下の式は常にfalseを返します。 ただし、このオブジェクトの既知のメソッドの1つ(または一度に複数)に依存することができます。たとえば、次の方法で確認できます。
if (obj.fire) { obj.add(fn); }
実際、この関数内では、クロージャーに依存する特定のメソッドセットを使用して通常のJSオブジェクトが作成されます。これは、この疑似コンストラクターの外部からアクセスできないプライベート変数を設定するかなり一般的なJavaScriptメソッドです。
また、このような疑似コンストラクターのおかげで、このオブジェクトのメソッドは呼び出しコンテキスト(それらが属するオブジェクト)に依存しません。つまり、コンテキストを変更することを心配せずに別のオブジェクトのプロパティに安全に割り当てることができます。 これは
fire
を除くすべてのメソッドに当てはまります。コンテキストに依存するだけですが、リストからコールバックを実行するためのコンテキストとして使用します。 場合によっては、このメソッドは単に可能ではありませんが、コンテキストを変更して別のオブジェクトのプロパティを割り当てる必要があります。 例:
var c = $.Callbacks(), obj = {}; obj.register = c.add; obj.register(function() { console.log('fired'); }); c.fire(); // output: 'fired'
旗
注 :以降、「fire()
メソッドを呼び出す」という言葉は、fireWith()
メソッドを含む、リストからコールバックを実行する呼び出しを意味します。
flags
コンストラクターパラメーターは、スペースで区切られたフラグ、作成された
callbacks
オブジェクトが機能するオプションを指定できる行です。 次のフラグがサポートされています。
once-コールバックのリストは1回しか実行できないことを示し、
fire()
メソッドの2回目以降の呼び出しは決定的ではありません(遅延オブジェクトで行われるように)。このフラグが指定されていない場合、
fire()
メソッドを数回呼び出すことができます
メモリ
fire()
メソッドの最後の呼び出しのパラメーターを覚えて(そしてリストからコールバックを実行し
fire()
、
fire()
メソッドが呼び出された後に追加された場合、対応するパラメーターで追加されたコールバックをすぐに実行する必要があることを示します(遅延オブジェクトで行われます)
unique-各コールバックをリストに一度だけ追加できることを示します。リストにコールバックを繰り返し追加しようとしても何も起こりません。
stopOnFalse-リストのコールバックのいずれかが、
fire()
呼び出しの現在のセッション内で
false
返した場合、リストからのコールバックを停止することを示します。
fire()
メソッドへの次の呼び出しは、新しいコールバックリスト実行セッションを開始し、リストの1つが
false
か終了するまで、それらは再び実行されます。
方法
以下に、簡単な説明を含むメソッドのリストを示します。例は公式のドックにあり、次のセクションのメソッドの一部です。 一般に、メソッドは非常にシンプルで、期待どおりに動作します。
callbacks.add(コールバック) は以下を返します:callbacks-コールバックをリストに追加します。このメソッドの引数にいくつかの関数(複数の引数)または関数配列(同時に両方)を渡すことができ、ネストされた配列を渡すこともできます。 関数ではないすべての引数(または配列要素)は、単に無視されます。 メソッド(これとそれ以上)はその呼び出しのコンテキストを返すので、jQueryで慣例となっているように、1つのオブジェクトの複数のメソッドの呼び出しのチェーンを連続して整理できます。
callbacks.remove(callbacks) は以下を返します。callbacks-リストからコールバックを削除します。コールバックが2回追加された場合でも、両方の位置から削除されます。 T.O. リストからコールバックを削除するメソッドを呼び出すと、追加された回数に関係なく、コールバックがリストにないことを確認できます。 複数の引数を複数の引数として同時に渡すことができます。配列を渡すことはできません。非関数へのすべての引数は無視されます。
callbacks.has(コールバック) 戻り値:ブール -指定された関数がコールバックリストにあるかどうかを確認します。
callbacks.empty() 戻り値:callbacks-コールバックリストをクリアします 。
callbacks.disable() 戻り値:callbacks-コールバックオブジェクトを「切断」します。これを使用したすべてのアクションは失敗します。 この場合、すべてのメソッドはまったく機能しなくなります
false
何にもつながりません、has-常に
false
を返し
false
。
callbacks.disabled() 戻り値:boolean -
disable()
を呼び出した後にコールバックオブジェクトが無効かどうかをチェックし、
true
を返し
true
。
callbacks.lock() 戻り値:callbacks-コールバックリストのパラメーターと実行ステータスに関連するコールバックオブジェクトの現在の状態をキャプチャします。 このメソッドは、 メモリフラグを使用する場合に有効であり、
fire()
への後続の呼び出しのみをブロックすることを意図しています。
具体的には、このメソッドは次のように機能します: メモリフラグが指定されていない場合、またはfire()
メソッドが呼び出されていない場合、最後のコールバックセッションがそれらのいずれかによってfalse
返すfalse
中断された場合、lock()
呼び出しはdisable()
呼び出しと同等です(呼び出されることです)この場合、disabled()
呼び出しはtrue
を返しtrue
。それ以外の場合、fire()
後続の呼び出しのみがブロックされます-コールバックの実行も、追加されたコールバックの実行パラメーターの変更( メモリフラグの存在下)も行われません。
callbacks.locked() 戻り値:boolean -
lock()
メソッドを使用してコールバックオブジェクトがロックされているかどうかを確認し、
disable()
呼び出された後に
true
も返し
true
。
callbacks.fireWith([context] [、args]) 戻り値:callbacks-指定されたコンテキストと引数を使用して、リスト内のすべてのコールバックの実行を開始します。 context-コールバック実行のコンテキスト(関数内で
this
を介し
this
アクセス可能なオブジェクト)を示します。 args-コールバックに渡される引数の配列(つまり配列)。
callbacks.fire(引数) 戻り値:callbacks-このメソッドの呼び出しコンテキストと引数を使用して、リスト内のすべてのコールバックの実行を開始します。 arguments-引数のリスト(
fireWith()
メソッドのような配列ではありません)。 つまり 呼び出しコンテキストとコールバック引数は、
fire()
メソッドのコンテキストと引数です。
同じパラメーターとコンテキストでコールバックの実行を同等に開始する方法の例:
var callbacks = $.Callbacks(), context = { test: 1 }; callbacks.add(function(p, t) { console.log(this.test, p, t); }); callbacks.fireWith(context, [ 2, 3 ]); // output: 1 2 3 context.fire = callbacks.fire; context.fire(2, 3); // output: 1 2 3
リストからのコールバックは、このリストに追加された順序で実行されます。 指定されたフラグでコールバックが1回実行された後、リストはクリアされ、 メモリフラグが指定されていないか、
false
を返す
false
でコールバックが中断され
false
場合、コールバックオブジェクトは
disable()
メソッドによって無効にされます。
例
例でフラグがどのように機能するかを見てみましょう。 すべての例で次の関数を使用します。
function fn1( value ){ console.log( value ); } function fn2( value ){ fn1("fn2 says:" + value); return false; }
$ .Callbacks():
var callbacks = $.Callbacks(); callbacks.add( fn1 ); callbacks.fire( "foo" ); callbacks.add( fn2 ); callbacks.add( fn1 ); callbacks.fire( "bar" ); callbacks.remove( fn2 ); callbacks.fire( "foobar" ); console.log(callbacks.disabled()); /* output: foo bar fn2 says:bar bar foobar foobar false */
フラグは示されていません-非常に期待される動作です。
$ .Callbacks( 'once'):
var callbacks = $.Callbacks( "once" ); callbacks.add( fn1 ); callbacks.fire( "foo" ); callbacks.add( fn2 ); callbacks.add( fn1 ); callbacks.fire( "bar" ); callbacks.remove( fn2 ); callbacks.fire( "foobar" ); console.log(callbacks.disabled()); /* output: foo true */
ここではすべてが明確です-いったん何が完了しても、何をしたとしても何も起こりません。 リストはすでに無効になっています。
$ .Callbacks( 'メモリ'):
var callbacks = $.Callbacks( "memory" ); callbacks.add( fn1 ); callbacks.fire( "foo" ); callbacks.add( fn2 ); callbacks.add( fn1 ); callbacks.fire( "bar" ); callbacks.remove( fn2 ); callbacks.fire( "foobar" ); console.log(callbacks.disabled()); /* output: foo fn2 says:foo foo bar fn2 says:bar bar foobar foobar false */
ここでは、それほど複雑ではないようです。最初の実行後、コールバックを追加するたびにすぐに実行され、再びリスト全体の実行を呼び出します。 同時に、1つの関数をリストに2回追加しました-2回機能します。
$ .Callbacks(「ユニーク」):
var callbacks = $.Callbacks( "unique" ); callbacks.add( fn1 ); callbacks.fire( "foo" ); callbacks.add( fn2 ); callbacks.add( fn1 ); callbacks.fire( "bar" ); callbacks.remove( fn2 ); callbacks.fire( "foobar" ); console.log(callbacks.disabled()); /* output: foo bar fn2 says:bar foobar false */
この場合、関数
fn1
繰り返しの追加は無視されました。
$ .Callbacks( 'stopOnFalse'):
var callbacks = $.Callbacks( "stopOnFalse" ); callbacks.add( fn1 ); callbacks.fire( "foo" ); callbacks.add( fn2 ); callbacks.add( fn1 ); callbacks.fire( "bar" ); callbacks.remove( fn2 ); callbacks.fire( "foobar" ); console.log(callbacks.disabled()); /* output: foo bar fn2 says:bar foobar foobar false */
fn2
は実行チェーンを中断し
fn2
、なぜなら
false
返し
false
。
これらは簡単な例であり、フラグの組み合わせをいじってみましょう。もう少しおもしろいでしょう。
$ .Callbacks( 'once memory'):
var callbacks = $.Callbacks( "once memory" ); callbacks.add( fn1 ); callbacks.fire( "foo" ); callbacks.add( fn2 ); callbacks.add( fn1 ); callbacks.fire( "bar" ); callbacks.remove( fn2 ); callbacks.fire( "foobar" ); console.log(callbacks.disabled()); /* output: foo fn2 says:foo foo false */
最初の
fire()
のみが機能し、新しいコールバックの追加により、最初の
fire()
パラメーターを使用した即時実行が行われたことがわかります。
$ .Callbacks( 'once memory unique'):
var callbacks = $.Callbacks( "once memory unique" ); callbacks.add( fn1 ); callbacks.fire( "foo" ); callbacks.add( fn2 ); callbacks.add( fn1 ); callbacks.fire( "bar" ); callbacks.remove( fn2 ); callbacks.fire( "foobar" ); console.log(callbacks.disabled()); /* output: foo fn2 says:foo foo false */
ここで結果は同じです。 一意のフラグを指定して
fn1
2回追加し
fn1
たが、2回目はこの関数をリストに追加しましたが、コールバックの実行後に指定したフラグを1回使用すると、リストがクリアされ、 メモリフラグはコールバックの追加を示しますリストに配置されずに即座に実行されます。リストは空なので、関数の追加は常に一意です。 ただし、以下に示すように前のコードの4行目を変更すると、
fn2
一度だけ実行されます( 一意のフラグなしでは3つが実行されます)回):
callbacks.add( fn2, fn2, fn2 );
$ .Callbacks( 'once memory stopOnFalse'):
var callbacks = $.Callbacks( "once memory stopOnFalse" ); callbacks.add( fn1 ); callbacks.fire( "foo" ); callbacks.add( fn2 ); callbacks.add( fn1 ); callbacks.fire( "bar" ); callbacks.remove( fn2 ); callbacks.fire( "foobar" ); console.log(callbacks.disabled()); /* output: foo fn2 says:foo true */
false
返すと、後続のすべてのコールバックがブロックされ、 onceフラグが存在する場合、通常はコールバックオブジェクトが無効になります。
フラグの考えられるすべての組み合わせを検討するわけではありません。最も興味深い(非常に単純ではない)を選択し、コールバックの動作を説明しようとしました。 残りの組み合わせは、たとえばブランクを使用して、個別にテストできます: http : //jsfiddle.net/zandroid/JXqzB/
約束された改善
もちろん、改善は絶対に必須ではなく、おそらく、ある程度まではとてつもなく厳しく判断することすらありません。
改善のアイデアは、
fire()
メソッド呼び出しを省略し、代わりにコールバックオブジェクトを関数として使用することです。 これを行うには、次の関数を記述します。
(function($, undefined){ $.FCallbacks = function(flags, fns) { var i = $.type(flags) === 'string' ? 1 : 0, callbacks = $.Callbacks(i ? flags : undefined); callbacks.add(Array.prototype.slice.call(arguments, i)) return $.extend(callbacks.fire, callbacks, { fcallbacks: true }); }; })(jQuery);
さらに苦労せずに、使用例を見てみましょう。
function fn1(p1, p2) { console.log('fn1 says:', this, p1, p2); } function fn2(p1, p2) { console.log('fn2 says:', this, p1, p2); } var callbacks = $.FCallbacks('once', fn1, rn2); callbacks.add(fn2); callbacks(2, 3);
また、新しい「コンストラクター」には、
add()
を余分に呼び出すことなく、パラメーターの初期コールバックをすぐに渡す機会もありました。
まあ、職場で: jsfiddle.net/zandroid/RAVtF
来たる祝日を迎えて、ご清聴ありがとうございました。
UPD:
コメントから判断すると、このオブジェクトがjQuery内でどのように使用されるかについての情報はまだ省略されています。 「Deferredにした-これはそのようなフレームワークでのこのようなメソッドの2倍」または「このコールバックが必要な理由-jQueryライブラリをより重くするだけで、実際のアプリケーションを思い付かない」に関するコメント-私の意見では、これらはコメントではありません問題の本質を理解する。 以下、この点を明確にします。
実際の使用
コールバックは実際には非常に多くの jQuery 1.7+ユーザーによって使用されており 、新しい機能を作成したかったため、開発チームによって簡単にされませんでした。 この質問の連鎖と論理は非常に簡単です:
$.ajax()
メソッドはライブラリに実装されましたが、その性質上、特定のDeferredのアドオンに過ぎません-開発者はコードを改善し、メインの
$.ajax()
コードとは別に移動し
$.ajax()
テストの再利用と簡素化の可能性のため)このコードを公開しませんか(ライブラリユーザーにアクセスして文書化してください)-
$.Deferred
。
順番に、
$.Deferred
は最初は2(
done()
および
fail()
)でしたが、現在は
$.Deferred
内部コードとして作成されたコールバックを超える3つの(+まだ
progress()
)アドオンです。 また、開発者はこのコードを改良して
$.Deferred
から分離し、
$.Deferred
を介して後者を実装し
$.Callbacks
(ところで、
$.Deferred
ソースコードは、より明確で読みやすくなりました)。
結論:開発者は、新しい「役に立たない」機能を追加することを主な目標として設定せず、既存の内部コードを最適化し、同時にセカンダリを公開しますが、それほど有用な結果はありません。 そして、
$.ajax()
を使用するたびに-ご存知のように、
$.Deferred
を使用するため、
$.Deferred
を使用します。 これは実際の使用例です。