1

私が仕事のために構築しているWebサイトには、ユーザーが入力して一連の要素のデータに格納されているさまざまなフィールドを検索できる検索バーがあります。問題は、ブラウザが遅くなり、入力を開始したときに発生します。

私がやろうとしていたのは、jQuery Deferredオブジェクトを使用して、次のことです。入力ボックスにキーアップハンドラーを追加します。キーアップがトリガーされたら、まだ「保留中」である以前にトリガーされたキーアップを解決します。次に、現在のキーアップイベントの使用を続行します。入力値に基づいてすべてのマッチングを実行するkeyupイベント自体の内部では、現在のイベントがまだ保留中であるかどうかを常にチェックし、保留中でない場合は、そのイベントの残りをスキップすることになっています。

問題は、IE7のような遅いブラウザでも、各キーアップイベントがブロックされていることだと思われます。したがって、ユーザーが「テスト」と入力すると、「te」のキーアップイベントが表示される前に、「t」文字のイベント全体を終了しようとします。

問題は、どうすればキーアップイベントを非同期/非ブロッキングにすることができるのか、それともこれはほとんど不可能なのかということです。

例:

var search_values = new Array();
var deferred_searches = {};

function filterSearchResults(event) {
    var input_element = jq(event.target);
    var search_value = input_element.val();
    console.log('user just typed final letter in :' + search_value);
    for (var svi = 0; svi < search_values.length-1; svi++) {
        if (deferred_searches[search_values[svi]] !== undefined &&
            deferred_searches[search_values[svi]].state() == 'pending') {
            console.log('resolving ' + search_values[svi])
            deferred_searches[search_values[svi]].resolve(search_values[svi]);
        }
    }

    var result_list = jq('div#header_project_selection_result_list');
    var all_project_results = result_list.find('div.header_project_result');

    console.log('beginning search for "'+search_value+'"');
    if (search_value == '') {
        // Blank input value means show all results
    }
    else {
        // Non-blank value means search
        if (! startSearchFilter(search_value, all_project_results)) {
            return false; // this should return out of this current event handler
        }
    }
    console.log('ending search for "'+search_value+'"');
},

/**
 * Helper function that actually handles finding and hiding/showing results,
 * and highlighting found text.
 *
 * Uses jQuery for this functionality.
 *
 * @param       search_value                            string              The text the user has input
 * @param       all_project_results                     jQuery              A jQuery extended array of all project results to filter
 *
 * @return      tbr                                     boolean             Flag indicating whether the search was short circuited
 */
function startSearchFilter(search_value, all_project_results) {
    var tbr = true;

    search_values.push(search_value);
    deferred_searches[search_value] = jq.Deferred();
    deferred_searches[search_value].done(function(sv) {
        search_values = search_values.without(sv);
        console.log('done deferred search for "'+sv+'" - disabling');
    });

    var number_of_results_found = 0;
    var pr_count = all_project_results.length - 1;
    var regexp = new RegExp(search_value, 'im');
    for (var index = 0; index <= pr_count; index++) {
        if (deferred_searches[search_value].state() == 'pending') {
            // KEEP GOING
            var ext_project_result = all_project_results.eq(index);
            var result_data = ext_project_result.data();

            //console.log(search_value+" is in state '"+deferred_searches[search_value].state()+"'.....' all_project_results.each() [inside]");
            if (result_shown) {
                number_of_results_found++;
                // The input text has been found on data for the current project, so make sure we show that result row
                ext_project_result.addClass('filtered');
            }
            else if (ext_project_result.hasClass('filtered')) {
                // The input text has not been found, or the user is not an admin and can't view it, so hide that row
                ext_project_result.removeClass('filtered');
            }
            continue; // keep going to the next result element
        }
        else {
            tbr = false;
            break; // break when short circuited
        }
    }
    if (deferred_searches[search_value].state() == 'pending') {
        deferred_searches[search_value].resolve(search_value); // explicitly resolve this finalized one
    }

    return tbr;
}

理論的にはこれは機能するはずですが、前述したように、常にブロックされているようです。

4

1 に答える 1

2

自分がしていることをするのではなく、「デバウンス」と呼ばれる概念を調べたいと思うかもしれません。これは基本的に、複数回呼び出すことができるが、一定量呼び出されないと完全に実行される関数を作成できるようにするものです。時間の。

(次のコードスニペットはunderscore.jsからのものです)

// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
var debounce = function(func, wait, immediate) {
    var timeout;
    return function() {
        var context = this, args = arguments;
        var later = function() {
            timeout = null;
            if (!immediate) {
                func.apply(context, args);
            }
        };
        if (immediate && !timeout) {
            func.apply(context, args);
        }

        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
    };
};

それを使用して、ユーザーが入力を停止してから500ミリ秒後にのみ高価なコールバックを実行するこのようなことを行うことができます

$( "#searchbox" ).keyup( debounce(function() {
    // Some expensive operation here
}, 500));

これを提供するBenAlmanによる優れたプラグイン(http://benalman.com/projects/jquery-throttle-debounce-plugin/)があります。または、LoDash / Underscoreを使用している場合は、同じ機能を提供します。

于 2012-09-22T04:08:50.620 に答える