如何在用户键入时防止keyup功能滞后



我正试图在jQuery:中创建一个搜索函数

$('input').on('keyup', function(){
var searchTerm = $("input").val().toLowerCase();
$('.item').each(function(){
if ($(this).filter('[data-text *= ' + searchTerm + ']').length > 0 || searchTerm.length < 1) {
$(this).parent().show();
} else {
$(this).parent().hide();
}
});
});

每次用户输入时,都会将其与.itemdiv的数据属性值进行比较。如果该元素的数据属性包含搜索查询,它就会被显示,否则就会被隐藏。

这在Chrome中运行得很好,但在Safari中由于某种原因,当用户输入时,它确实很滞后。

有办法解决这个问题吗?

大约有1400个div(.item),每个元素的data-text属性只有大约10-20个字符

编辑,通过删除.show().hide()并替换为本地Javascript 修复

解决方案

我以前也遇到过类似的问题,我想你可能想尝试添加一个名为";去跳动";,这基本上在进行任何处理之前增加了延迟。在keyup的情况下,它将等待用户在任何设定的时间内停止键入(比如0.5秒),然后执行该过程(搜索或其他)。如果不使用debounce,它将在用户每次触发keyup事件时执行搜索。

你可以搜索关于如何做debounce的文章,我想有很多。但本质上它使用了JS 的setTimeoutclearTimeout函数

以下是我发现的第一篇文章:https://levelup.gitconnected.com/debounce-in-javascript-improve-your-applications-performance-5b01855e086

const debounce = (func, wait) => {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
};

如何使用此功能?简单地说,只需将实际函数(搜索函数)添加为第一个参数,并在第二个参数中添加延迟(微秒),然后使用.call()函数(为什么要这样做?因为debounce会返回一个函数)。所以我猜是这样的:

$('input').on('keyup', function(){
var searchTerm = $("input").val().toLowerCase();
debounce(function(){
$('.item').each(function(){
if ($(this).filter('[data-text *= ' + searchTerm + ']').length > 0 || searchTerm.length < 1) {
$(this).parent().show();
} else {
$(this).parent().hide();
}
});
}, 500).call();
});

这就是我要做的,因为这样我就可以在keyup事件中添加一些debounce之外的东西,但你可以把debounce返回的函数放在一个变量中,然后把它与keyup绑定(就像在文章中一样),或者直接把debouce放在keyup内部,就像这样:

$('input').on('keyup', debounce(function(){
...
},500));

它是如何工作的

你可以在文章中阅读它们,或者在StackOverflow中找到答案,这是我得到的;去跳动";Javascript 中的函数

但如果我用我自己的话来说,基本上你首先需要理解的是setTimeout在调用函数之前设置一个计时器,clearTimeout取消该计时器。现在在debounce中,你可以看到在任何setTimeout之前都有一个clearTimeout。因此,每次触发keyup事件时,它基本上都会取消上次设置的超时(如果有的话),然后再设置一个新的超时。本质上,它会将计时器重置为每次触发事件时设置的值。

例如:

  1. 用户想要搜索";abc">
  2. 他们键入";a"->debounce在调用实际搜索";a">
  3. 在500ms结束之前;b";,所以去跳动消除了";a";搜索和搜索";ab";相反,同时在操作之前设置500毫秒的计时器
  4. 在500ms结束之前;c";,因此取消";ab";搜索,添加500ms的定时器来搜索";abc">
  5. 用户停止键入直到500ms结束,现在debounce实际上调用了搜索";abc">

结果是什么?用于搜索的重处理只进行一次;abc";,你也可以在这个繁重的处理中放入一个加载器或其他东西,这样对用户来说会更好

一些快速修复:

  • 对div进行排序,然后在each之后的单个语句中显示/隐藏,而不是每次迭代

更改DOM的成本相对较高,因此在一条语句中这样做可以大大提高的性能

  • 如果这是table更改为divs

表需要对小的更改重新呈现整个表。固定单元格大小会有所帮助。不是这个问题的情况,只是的总体改进

  • 使用内存中的过滤器,而不是读取每个项的DOM

读取DOM的速度比在内存中慢得多(当然,在内存中会使用更多的内存)。例如,在.data()上进行筛选,而不是在内存中使用[data-]。这在Chrome中可能很快,因为Chrome可能正在缓存[data-属性,所以在Chrome 中可能没有改进

  • 取消对输入事件的抖动,使其仅在用户完成键入时发生

等待,直到用户";成品";键入然后运行操作。

  • 使用运算符关联性

虽然是边缘情况,但这条线

if ($(this).filter('[data-text *= ' + searchTerm + ']').length > 0 || searchTerm.length < 1)

即使在searchTerm.length < 1时也将运行$(this).filter,更改为

if (searchTerm.length < 1 || $(this).filter('[data-text *= ' + searchTerm + ']').length > 0)

运行示例

function a() { console.log("a"); return true; }
function b() { console.log("b"); return true; }  // b() doesn't need to exist
if (a() || b()) console.log("c")

  • 考虑服务器端分页/筛选

显著降低了;足迹";在页面上,so将更快/更响应,但检索数据的延迟可能会稍长。根据它的显示方式,1400条记录对用户来说可能是一次查看的大量记录(因此您可以进行筛选)。

最新更新