8

特定の Ajax イベントが非同期的にトリガーされる Web ページがあります。この Ajax セクションは、1 回または複数回呼び出すことができます。このイベントがトリガーされる回数やタイミングを制御することはできません。

また、その Ajax セクションには、クリティカル セクションとして実行する必要がある特定のコードがあります。つまり、実行中は、そのコードの他のコピーを実行してはなりません。

擬似コードは次のとおりです。

  1. JavaScript または jQuery コードを実行する
  2. Ajax であるクリティカル セクションを入力します (特定のプロセスが応答コールバックを待機している場合、このプロセスが完了するまで、このセクションには再度入力しないでください)。
  3. より多くの JavaScript または jQuery コードを実行する

私の質問は、上記の方法でステップ 2 を実行するにはどうすればよいですか? JavaScript または jQuery を使用して相互排除セクションを作成/保証するにはどうすればよいですか?

理論 (セマフォ、ロックなど) は理解していますが、JavaScript や jQuery を使用してソリューションを実装することはできませんでした。

編集

クリティカル セクションに入るためにブール変数を提案している場合、これは機能しません。以下の行でその理由を説明します。

クリティカル セクションのコードは次のようになります (ブール変数の提案を使用)。

load_data_from_database = function () {

    // Load data from the database. Only load data if we almost reach the end of the page
    if ( jQuery(window).scrollTop() >= jQuery(document).height() - jQuery(window).height() - 300) {

        // Enter critical section
        if (window.lock == false) {

            // Lock the critical section
            window.lock = true;

            // Make Ajax call
            jQuery.ajax({
                type:        'post',
                dataType:    'json',
                url:         path/to/script.php,
                data:        {
                    action:  'action_load_posts'
                },
                success:     function (response) {
                    // First do some stuff when we get a response

                    // Then we unlock the critical section
                    window.lock = false;
                }

            });


            // End of critical section
        }
    }
};

// The jQuery ready function (start code here)
jQuery(document).ready(function() {
    var window.lock = false; // This is a global lock variable

    jQuery(window).on('scroll', load_data_from_database);
});

これは、ブール変数を使用して提案されたロック セクションのコードです。これは、以下に示すようには機能しません。

  1. ユーザーが下にスクロールします (関連付けに基づいて、jQuery(window).on('scroll', load_data_from_database);複数のスクロール イベントがトリガーされます。

  2. 2 つのスクロール イベントがほぼ同時にトリガーされたとします。

  3. load_data_from_databaseどちらも関数を呼び出します

  4. window.lock最初のイベントは、かどうかをチェックします(答えは真なので、ステートメントが正しい場合)

  5. window.lock2 番目のイベントは、かどうかをチェックします(答えは真なので、ステートメントが正しい場合)。

  6. 最初のイベントが if ステートメントに入る

  7. 2 番目のイベントが if ステートメントに入る

  8. 最初のステートメントはtruewindow.lockに設定されます

  9. 2 番目のステートメントはtruewindow.lockに設定されます

  10. 最初のステートメントは Ajax クリティカル セクションを実行します

  11. 2 番目のステートメントは、Ajax クリティカル セクションを実行します。

  12. どちらもコードを終了します

お気づきのように、両方のイベントがほぼ同時にトリガーされ、両方ともクリティカル セクションに入ります。したがって、ロックはできません。

4

3 に答える 3

2

一度に 1 つのアイテムしか実行できないキューをお勧めします。これには、重要な機能にいくつかの変更が必要になります (それほどではありませんが)。

function critical(arg1, arg2, completedCallback) {
    $.ajax({
        ....
        success: function(){
            // normal stuff here.
            ....

            // at the end, call the completed callback
            completedCallback();
        }
    });
}

var queue = [];
function queueCriticalCalls(arg1, arg2) {
    // this could be done abstractly to create a decorator pattern
    queue.push([arg1, arg2, queueCompleteCallback]);

    // if there's only one in the queue, we need to start it
    if (queue.length === 1) {
        critical.apply(null, queue[0]);
    }


    // this is only called by the critical function when one completes
    function queueCompleteCallback() {
        // clean up the call that just completed
        queue.splice(0, 1);

        // if there are any calls waiting, start the next one
        if (queue.length !== 0) {
            critical.apply(null, queue[0]);
        }
    }
}

更新: jQuery の Promiseを使用した代替ソリューション(jQuery 1.8+ が必要)

function critical(arg1, arg2) {
    return $.ajax({
        ....
    });
}

// initialize the queue with an already completed promise so the
// first call will proceed immediately
var queuedUpdates = $.when(true);

function queueCritical(arg1, arg2) {
    // update the promise variable to the result of the new promise
    queuedUpdates = queuedUpdates.then(function() {
        // this returns the promise for the new AJAX call
        return critical(arg1, arg2);
    });
}

はい、よりクリーンなコードの約束が実現しました。:)

于 2014-03-03T16:32:19.037 に答える