优化正则表达式以筛选数千个HTML选择选项



背景

我为HTMLselect元素开发了一个基于jQuery的shuttle小部件,因为我找不到一个编码最少的小部件,并且提供了一个正则表达式过滤器来补偿变音符号。

问题

当向select添加几千个条目时,正则表达式筛选器的速度会减慢到爬网。您可以看到以下问题:

  1. 浏览到:http://jsfiddle.net/U8Xre/2/
  2. 单击结果面板中的输入字段
  3. 键入任意正则表达式(例如,^a.*ai)

代码

我相信罪魁祸首就潜伏在这里:

var options = $src.empty().scrollTop( 0 ).data( "options" );
var search = $.trim( $input.val() );
var regex = new RegExp( search, 'gi' );
var len = options.length;
var $html = $(document.createElement( 'option' ));
for( var i = 0; i < len; i++ ) {
var o = options[ i ];
if( o.text.dediacritics().match( regex ) !== null ) {
$src.append( $html.clone().text( o.text ).val( o.value ) );
}
}
$src.css( 'width', $input.width() + 4 );

其中$src是源$('#select')并且String.prototype.dediacritics被定义为在小提琴中。上面的代码对每个按键都会运行。还有一个相关的片段:

// Create a copy of the source options to use when matching the regex.
var $options = [];
$src.find( "option" ).each( function() {
$options.push( { value: $(this).val(), text: $(this).text() } );
});
$src.data( "options", $options );

这将复制源列表中的选项,但只运行一次。(这会导致在切换选项时出现重复错误,但将上述代码添加到input事件处理程序中会使过滤器速度减慢。)

问题

如何使代码几乎实时地对多达5000个单词的列表执行正则表达式过滤?

谢谢!

我想更难的工作是重复调用dediacritics()(用它的许多正则表达式替换),而不是进行搜索(尽管我还没有进行任何分析)。因此,您应该缓存这些去变音符号化的字符串,并只搜索它们。顺便说一句,test通常比match快。

此外,您应该避免尽可能多的DOM操作——在按键清空和重新追加整个选项列表时,会有很多DOM操作。

// once:
var options = [],
src = $src[0]; // or whatever to get the DOM element
$.each( src.options, function() {
options.push( { el: this, text: $(this).text().dediacritics(), hidden:false } );
});
// you might put it on the element via .data(), but need not
// onkeypress:
var regex = new RegExp( $.trim($input.val()), 'i' );
var curEl = src.firstChild;
for (var i=0; i<options.length; i++) {
var option = options[i];
if (regex.test( option.text )) {
if (option.hidden)
src.insertBefore(option.el, curEl);
curEl = option.el.nextSibling;
option.hidden = false;
} else {
if (!option.hidden) {
curEl = option.el.nextSibling;
src.removeChild(option.el);
}
option.hidden = true;
}
}

Demo:这非常快("实时"),但当调用dediacritics()5000次时,您可以感觉到构建options阵列所需的时间。

我建议你去

  • 创建一个包含所有选项名称列表的多行字符串,每个名称在单独的一行中
  • 将regex应用于此多行字符串,通过删除不匹配的行来过滤其内容
  • 使用匹配行作为select元素的选项更新html

一个小注释,如果您没有使用正则表达式匹配的结果,那么您应该使用正则表达式测试:

if( o.text.dediacritics().match( regex ) !== null ) {

使用测试:

if( regex.test(o.text.dediacritics()) ) {

最新更新