ホームページ >ウェブフロントエンド >jsチュートリアル >jQuery ソース コードのコールバックについて学習する

jQuery ソース コードのコールバックについて学習する

不言
不言オリジナル
2018-07-09 10:57:341364ブラウズ

この記事は主に jQuery ソースコードのコールバックの学習を紹介します。これには一定の参考価値がありますので、必要な友達に共有してください

jQuery の ajax、<code>deferred はコールバックを介して非同期に実装され、その実装の中核は Callbacks です。

使用方法

これを使用するには、まず新しいインスタンス オブジェクトを作成する必要があります。作成時に、コールバック オブジェクトの制限を示すパラメータ flags を渡すことができます。オプションの値は次のとおりです。 ajaxdeferred通过回调实现异步,其实现核心是Callbacks

使用方法

使用首先要先新建一个实例对象。创建时可以传入参数flags,表示对回调对象的限制,可选值如下表示。

  • stopOnFalse:回调函数队列中的函数返回false时停止触发

  • once:回调函数队列只能被触发一次

  • memory:记录上一次触发队列传入的值,新添加到队列中的函数使用记录值作为参数,并立即执行。

  • unique:函数队列中函数都是唯一的

var cb = $.Callbacks(&#39;memory&#39;);
cb.add(function(val){
    console.log(&#39;1: &#39; + val)
})
cb.fire(&#39;callback&#39;)
cb.add(function(val){
    console.log(&#39;2: &#39; + val)
})
// console输出
1: callback
2: callback

Callbacks 提供了一系列实例方法来操作队列和查看回调对象的状态。

  • add: 添加函数到回调队列中,可以是函数或者函数数组

  • remove: 从回调队列中删除指定函数

  • has: 判断回调队列里是否存在某个函数

  • empty: 清空回调队列

  • disable: 禁止添加函数和触发队列,清空回调队列和上一个传入的值

  • disabled: 判断回调对象是否被禁用

  • lock: 禁用fire,若memory非空则同时add无效

  • locked: 判断是否调用了lock

  • fireWith: 传入context和参数,触发队列

  • fire: 传入参数触发对象,context是回调对象

源码解析

$.Callback()方法内部定义了多个局部变量和方法,用于记录回调对象的状态和函数队列等,返回self,在self实现了上述回调对象的方法,用户只能通过self提供的方法来更改回调对象。这样的好处是保证除了self之外,没有其他修改回调对象的状态和队列的途径。

其中,firingIndex为当前触发函数在队列中的索引,list是回调函数队列,memory记录上次触发的参数,当回调对象实例化时传入memory时会用到,queue保存各个callback执行时的context和传入的参数。self.fire(args)实际是self.fireWith(this,args)self.fireWith内部则调用了在Callbacks定义的局部函数fire

    ...
    // 以下变量和函数 外部无法修改,只能通过self暴露的方法去修改和访问
    var // Flag to know if list is currently firing
        firing,

        // Last fire value for non-forgettable lists
        // 保存上一次触发callback的参数,调用add之后并用该参数触发
        memory,

        // Flag to know if list was already fired
        fired,

        // Flag to prevent firing
        // locked==true fire无效 若memory非空则同时add无效
        locked,

        // Actual callback list
        // callback函数数组
        list = [],

        // Queue of execution data for repeatable lists
        // 保存各个callback执行时的context和传入的参数
        queue = [],

        // Index of currently firing callback (modified by add/remove as needed)
        // 当前正触发callback的索引
        firingIndex = -1,

        // Fire callbacks
        fire = function() {
            ...
        },
        
        // Actual Callbacks object
        self = {
            // Add a callback or a collection of callbacks to the list
            add: function() {
                ...
            },
            ...
            // Call all callbacks with the given context and arguments
            fireWith: function( context, args ) {
                if ( !locked ) {
                    args = args || [];
                    args = [ context, args.slice ? args.slice() : args ]; // :前为args是数组,:后是string
                    queue.push( args );
                    if ( !firing ) {
                        fire();
                    }
                }
                return this;
            },

            // Call all the callbacks with the given arguments
            fire: function() {
                self.fireWith( this, arguments );
                return this;
            },
            ...
        }

通过self.add添加函数到回调队列中,代码如下。先判断是否memory且非正在触发,如果是则将fireIndex移动至回调队列的末尾,并保存memory。接着使用立即执行函数表达式实现add函数,在该函数内遍历传入的参数,进行类型判断后决定是否添加到队列中,如果回调对象有unique标志,则还要判断该函数在队列中是否已存在。如果回调对象有memory标志,添加完毕之后还会触发fire,执行新添加的函数。

            add: function() {
                if ( list ) {

                    // If we have memory from a past run, we should fire after adding
                    // 如果memory非空且非正在触发,在queue中保存memory的值,说明add后要执行fire
                    // 将firingIndex移至list末尾 下一次fire从新add进来的函数开始
                    if ( memory && !firing ) {
                        firingIndex = list.length - 1;
                        queue.push( memory );
                    }

                    ( function add( args ) {
                        jQuery.each( args, function( _, arg ) {
                            // 传参方式为add(fn)或add(fn1,fn2)
                            if ( jQuery.isFunction( arg ) ) {
                                /**
                                 * options.unique==false
                                 * 或
                                 * options.unique==true&&self中没有arg
                                 */
                                if ( !options.unique || !self.has( arg ) ) {
                                    list.push( arg );
                                }
                            } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) {
                                // 传参方式为add([fn...]) 递归
                                // Inspect recursively
                                add( arg );
                            }
                        } );
                    } )( arguments ); //arguments为参数数组 所以add的第一步是each遍历

                    //添加到list后若memory真则fire,此时firingIndex为回调队列的最后一个函数
                    if ( memory && !firing ) {
                        fire();
                    }
                }
                return this;
            }

firefireWith方法内部实际调用了局部函数fire,其代码如下。触发时,需要更新firedfiring,表示已触发和正在触发。通过for循环执行队里中的函数。结束循环后,将firingIndex更新为-1,表示下次触发从队列中的第一个函数开始。遍历在fireWith中更新过的queuequeue是保存数组的数组,每个数组的第一个元素是context,第二个元素是参数数组。执行函数时要是否返回false且回调对象有stopOnFalse

  • stopOnFalse: コールバック関数キュー内の関数が false を返した場合にトリガーを停止します

  • once: コールバック関数キューは 1 回だけトリガーできます

  • memory: 最後のトリガー キューに渡された値を記録します。新しく追加されました キューに配置された関数は、レコード値を引数として受け取り、すぐに実行されます。

  • unique: 関数キュー内の関数はすべて固有です

// Fire callbacks
        fire = function() {

            // Enforce single-firing
            // 执行单次触发
            locked = locked || options.once;

            // Execute callbacks for all pending executions,
            // respecting firingIndex overrides and runtime changes
            // 标记已触发和正在触发
            fired = firing = true;
            // 循环调用list中的回调函数
            // 循环结束之后 firingIndex赋-1 下一次fire从list的第一个开始 除非firingIndex被修改过
            // 若设置了memory,add的时候会修改firingIndex并调用fire
            // queue在fireWith函数内被更新,保存了触发函数的context和参数
            for ( ; queue.length; firingIndex = -1 ) {
                memory = queue.shift();
                while ( ++firingIndex < list.length ) { 

                    // Run callback and check for early termination
                    // memory[0]是content memory[1]是参数
                    if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&
                        options.stopOnFalse ) {
                        
                        // Jump to end and forget the data so .add doesn't re-fire
                        // 当前执行函数范围false且options.stopOnFalse==true 直接跳至list尾 终止循环
                        firingIndex = list.length;
                        memory = false;
                    }
                }
            }

            // 没设置memory时不保留参数
            // 设置了memory时 参数仍保留在其中
            // Forget the data if we're done with it
            if ( !options.memory ) {
                memory = false;
            }

            firing = false;

            // Clean up if we're done firing for good
            if ( locked ) {

                // Keep an empty list if we have data for future add calls
                if ( memory ) {
                    list = [];

                // Otherwise, this object is spent
                } else {
                    list = "";
                }
            }
        },
Callbacks は一連の例 キューを操作し、コールバック オブジェクトのステータスを表示するメソッド。

  • add: 関数をコールバック キューに追加します。関数または関数の配列を追加します
  • has: 関数がコールバック キューに存在するかどうかを判断します
    li>

  • empty: コールバック キューをクリアします🎜
  • 🎜disable: 関数とトリガー キューの追加を無効にし、コールバック キューと最後に受信した値🎜 li>
  • 🎜disabled: コールバック オブジェクトが無効かどうかを判断します🎜
  • 🎜lock: を無効にしますfire, if メモリが空でない場合、同時に追加は無効です🎜
  • 🎜locked: lock かどうかを判断します🎜
  • 🎜fireWith は と呼ばれます: context とパラメーターを渡してキューをトリガーします🎜
  • 🎜fire: パラメータを渡してオブジェクトをトリガーします。context code> はコールバック オブジェクトです🎜

ソース コード分析

🎜$.Callback() メソッドは記録用の複数のローカル変数とメソッドを定義します。 コールバック オブジェクトのステータスと関数キューは self に返されます。 上記のコールバック オブジェクトのメソッドは self に実装されます。ユーザーは、self メソッドによって提供されるメソッドのみを使用してコールバック オブジェクトを変更できます。この利点は、コールバック オブジェクトの状態とキューを変更する方法が self 以外にないことです。 🎜🎜その中で、firingIndex はキュー内の現在のトリガー関数のインデックス、list はコールバック関数のキュー、memory はコールバック関数のキューを記録します。最後のトリガーのパラメータ。コールバック オブジェクトがインスタンス化されるときに memory が渡されるときに使用され、各コールバックの実行時に渡されるコンテキストとパラメータが保存されます。 self.fire(args) は実際には self.fireWith(this, args) であり、self.fireWith は内部で Callbacks ローカル関数 <code>fire が定義されました。 🎜rrreee🎜 self.add を通じて関数をコールバック キューに追加します。コードは次のとおりです。まず、それが memory であるかどうかを確認し、トリガーされていない場合は、fireIndex をコールバック キューの最後に移動し、memory を保存します。次に、即時実行関数式を使用して add 関数を実装し、関数内の受信パラメーターを走査し、コールバック オブジェクトに unique フラグがある場合に型判定を実行した後にそれをキューに追加するかどうかを決定します。 、関数がすでにキューに存在するかどうかも判断する必要があります。コールバック オブジェクトに memory フラグがある場合、追加の完了後に fire がトリガーされ、新しく追加された関数が実行されます。 🎜rrreee🎜 fire メソッドと fireWith メソッドは実際にローカル関数 fire を呼び出します。コードは次のとおりです。トリガーされると、firedfiring を更新して、トリガーされたこと、およびトリガー中であることを示す必要があります。 for ループを通じてキュー内の関数を実行します。ループの終了後、firingIndex を -1 に更新します。これは、次の起動がキュー内の最初の関数から開始されることを示します。 fireWith で更新された queue をスキャンします。 queue は、配列を保持する配列です。各配列の最初の要素は context です。 code> の 2 番目の要素はパラメータ配列です。関数の実行時に false を返すかどうか、コールバック オブジェクトに stopOnFalse フラグがある場合、トリガーを停止します。 🎜rrreee🎜 🎜🎜 以上がこの記事の全内容です。その他の関連コンテンツについては、PHP 中国語 Web サイトをご覧ください。 🎜🎜関連する推奨事項: 🎜🎜🎜js 非同期 for ループの概要🎜🎜🎜🎜🎜jQuery-Ajax は Json データをリクエストし、それをフロントエンド ページにロードします🎜🎜🎜

以上がjQuery ソース コードのコールバックについて学習するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。