Как использовать setTimeout / .delay () для ожидания ввода между символами - PullRequest
3 голосов
/ 26 мая 2010

Я создаю простой фильтр списка, который принимает пользовательский ввод и возвращает результаты сопоставления в списке через javascript / jquery (примерно 5000+ элементов в списке). Вот фрагмент кода:

var Listbox1 = $('#Listbox1');
var commands = document.getElementById('DatabaseCommandsHidden'); //using js for speed

$('#CommandsFilter').bind('keyup', function() {

Listbox1.children().remove();


for (var i = 0; i < commands.options.length; i++) {
    if (commands.options[i].text.toLowerCase().match($(this).val().toLowerCase())) {
        Listbox1.append($('<option></option>').val(i).html(commands.options[i].text));
    }
}
});

Это работает довольно хорошо, но несколько замедляется, когда набираются 1-й / 2-й символы, так как элементов очень много.

Я подумал, что решение, которое я мог бы использовать, это добавить задержку в текстовое поле, которая предотвращает вызов события keyup до тех пор, пока пользователь не перестанет печатать. Проблема в том, что я не уверен, как это сделать, или даже если это хорошая идея или нет.

Любые предложения / помощь с благодарностью.

Ответы [ 2 ]

6 голосов
/ 26 мая 2010

Вы можете сделать задержку следующим образом:

$('#CommandsFilter').keyup(function() {
  clearTimeout($.data(this, 'timer'));
  var wait = setTimeout(search, 500);
  $(this).data('timer', wait);
});

function search() {
  var temp = $("<select />");
  for (var i = 0; i < commands.options.length; i++) {
    if (commands.options[i].text.toLowerCase().match($(this).val().toLowerCase())) {
      $('<option></option>', { val: i, html: commands.options[i].text }).appendTo(temp);
    }
  }
  Listbox1.empty().append(temp.children());
}

Это сохраняет время ожидания для элемента, который вы вводите, если 500 мс (отрегулируйте при необходимости) между нажатиями клавиш, выполняется поиск. Также это добавляет элементы во фрагменте документа, затем в DOM (с сохранением кодировки и т. Д.). В зависимости от количества предметов, это может быть и приличное повышение производительности.

2 голосов
/ 26 мая 2010

Если раскрывающийся список команд не меняется, я бы предложил следующее (обратите внимание, что я упал jQuery для лучшей производительности и совместимости). Есть несколько улучшений:

  • Таймер для задержки обновления отфильтрованного списка через полсекунды с момента последнего нажатия клавиши
  • Список текстов команд предварительно кэшируется
  • Ненужное использование match заменено на indexOf
  • Использует быстрые собственные манипуляции с DOM, которые работают во всех скриптовых браузерах с 1990-х годов

Быстрый тест показывает, что для раскрывающегося списка с 5000 опциями, содержащими короткие строки, он в 10-30 раз быстрее, чем эквивалент jQuery в большинстве браузеров.

Код:

var commands = document.getElementById("DatabaseCommandsHidden");
var filteredDropDown = document.getElementById("Listbox1");
var filterInput = document.getElementById("CommandsFilter");
var timer;

// Create a cached list of the lower case text of the commands drop-down
var commandTexts = [], commandText;
for (var i = 0, len = commands.options.length; i < len; ++i) {
    commandText = commands.options[i].text;
    commandTexts.push({original: commandText, lower: commandText.toLowerCase()});
}

function populateFilteredDropDown() {
    timer = null;
    var val = filterInput.value.toLowerCase(), commandText;
    var opts = filteredDropDown.options;
    filteredDropDown.length = 0;
    for (var i = 0, len = commandTexts.length; i < len; ++i) {
        commandText = commandTexts[i];
        if (commandText.lower.indexOf(val) > -1) {
            opts[opts.length] = new Option(commandText.original);
        }
    }
}

filterInput.onkeyup = function() {
    if (timer) {
        window.clearTimeout(timer);
    }
    timer = window.setTimeout(populateFilteredDropDown, 500);
};
...