异步按键事件/如何使顺序按键事件短路以提高速度 [英] asynchronous keyup events/how to short circuit sequential keyup events for speed boost

查看:66
本文介绍了异步按键事件/如何使顺序按键事件短路以提高速度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我要工作的网站上,我们有一个搜索栏,用户可以在其中键入以搜索存储在一组元素上的数据中的各个字段.当浏览器开始输入速度较慢时,就会出现问题.

On the website I'm building for work, we have a search bar where the user can type in to search various fields stored in data on a set of elements. The problem comes in slower browsers, when they start typing.

我想使用jQuery Deferred对象执行以下操作:在输入框中添加一个向上键处理程序.触发加锁键时,请解决任何以前触发的仍处于待处理"状态的加锁键.然后继续使用当前的keyup事件.在keyup事件本身内部,它根据输入值进行所有匹配,它始终检查当前事件是否仍在等待处理,如果不是,则应跳过该事件的其余部分.

What I was trying to do is the following, using a jQuery Deferred object: add a key up handler to the input box. when the keyup is triggered, resolve any previously triggered keyups that are still 'pending'. then continue on using the current keyup event. Inside the keyup event itself where it's doing all the matching based on the input value, it always checks to see if the current event is pending still, and if it's not, it is supposed to skip the remainder of that event.

问题似乎是,即使使用IE7之类的慢速浏览器,每个keyup事件也会被阻止.因此,如果用户键入测试",它将尝试在看到"te"键事件之前完成"t"字符的整个事件,等等.

The problem seems to be that, even with slow browsers like IE7, each keyup event is blocking. So if the user types in "testing", it'll try to finish the entire event for the "t" character before it even sees the keyup event of "te", and so on.

问题就变成了,如何使键盘事件异步/非阻塞,或者这几乎是不可能的?

The question then becomes, how can I make the keyup events asynchronous/non-blocking, or is this pretty much impossible?

一个例子:

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;
}

从理论上讲这应该可行,但是正如我提到的那样,它似乎总是会阻塞.

In theory this should work but as I mentioned, it seems to always block.

推荐答案

您可能不想研究自己正在做的事情,而是希望研究一个名为"debounce"的概念,该概念基本上允许您创建可以被多个调用的函数.次,但只有在一定时间内没有被调用时,才会完全执行.

Rather than doing what you're doing, you might want to look into a concept called "debounce" which basically allows you create a function that can be invoked multiple times but will only fully execute once it hasn't been invoked for a certain amount of time.

(以下代码段来自underscore.js)

( The following code snippet is from 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毫秒执行昂贵的回调操作

Using that, you might do something like this which will only execute our expensive callback 500ms after the user stops typing

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

Ben Alman有一个很好的插件可以提供此功能( http://benalman. com/projects/jquery-throttle-debounce-plugin/)或LoDash/Underscore提供的功能相同.

There's a good plugin by Ben Alman that provides this ( http://benalman.com/projects/jquery-throttle-debounce-plugin/ ), or LoDash/Underscore provide the same functionality if you're using them.

这篇关于异步按键事件/如何使顺序按键事件短路以提高速度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆