提问人:Drew 提问时间:11/5/2020 最后编辑:Drew 更新时间:11/5/2020 访问量:497
在闭合内使用下划线去抖动功能
Using underscore debounce function inside closure
问:
我正在使用闭包来确保只对绑定到元素的众多事件中的一个采取行动,例如:$('.textInputs').on('keyup.my.evt change.my.evt', once(options));
我在函数闭包中使用下划线。如果我对一个输入进行更改并等待,然后再对另一个输入进行更改,一切正常。如果我在一个输入中进行了更改,然后快速切换到下一个输入,并在第一个输入的时间等待到期前的一秒钟内进行更改,则仅对第二个输入执行去抖动函数。这告诉我两个输入都使用从去抖动返回的相同函数,但我不确定如何更改我的代码结构,以便每个输入都使用自己的去抖动函数。_.debounce
once
去抖动函数:
var doStuff = function(eleObj, options){ console.log(eleObj, options); } // the function that does stuff
var debouncedDoStuff = _debounce(doStuff, 2000); // debouncing doStuff()
一次闭合定义:
var once = function (options) {
var eventType = null;
function doOnce(e) {
if (!eventType) {
eventType = e.type; // only the first eventType we get will be registered
}
if (e.type == eventType) {
debouncedDoStuff($(this), options); // calling the debounced do stuff func
}
}
return doOnce;
}
文档就绪:
$(document).ready(function(){
var options = {foo:'bar', baz:'biz'};
$('.textInputs').on('keyup.my.evt change.my.evt', once(options));
});
我做了一个小提琴来演示这个问题:https://jsfiddle.net/enzt7q90/
澄清说明上面的代码已减少到最低限度,显示了问题。实际目标是将 doStuff 附加到 ajax 进程,以保存对表格数据所做的任何更改。
我还应该指出,once 闭包不像 jQuery 的 .one()。例如,.one('keyup change', function(){}) 将在按下 Tab 键时执行 func 两次(一次用于 keyup,一次用于更改),而我使用 once 闭包的方式,该函数仅针对这两个事件执行一次。
答:
您可以通过将 传递 来创建一个去抖动版本。您的问题是您只执行一次此操作,因此事件处理程序必须在所有元素之间共享一个这样的去抖动版本。去抖动意味着只有一些调用实际上会到达原始函数。从本质上讲,您隐藏了所有调用,但最近的调用除外。doStuff
_.debounce
doStuff
我的印象是,当你实际触发时,你要考虑所有有变化的输入元素。您希望只处理这些元素中的每一个一次,而不管它触发了事件处理程序多少次。这意味着处理 () 应该像您所做的那样去抖动,但即时事件处理程序 () 必须以某种方式区分输入元素。doStuff
doStuff
doOnce
Boudy hesham 已经评论了一种可能的解决方案,即为每个输入注册一个单独的事件处理程序,其中包含一个单独的去抖动版本:doStuff
var doStuff = function(eleObj, options){ console.log(eleObj, options); } // same as before
function once(options) {
// Note that the debounced function is now generated inside the
// event handler factory.
var debouncedDoStuff = _.debounce(doStuff, 2000);
function doOnce(e) {
// We don't need to restrict the event type anymore, because
// this event handler is specific to a single input element.
// The debounce already ensures that `doStuff` is called only once
// for this element.
debouncedDoStuff($(this), options);
}
return doOnce;
}
$(document).ready(function(){
var options = {foo:'bar', baz:'biz'};
// Using jQuery's .each to generate an event handler for each input
// element individually.
$('.textInputs').each(function() {
$(this).on('keyup.my.evt change.my.evt', once(options));
});
});
另一种选择是保留触发事件的所有输入元素的列表,并在超时后最终运行时删除重复数据:doStuff
var doStuff = function(elementList, options){
var uniqueElements = _.uniq(elementList);
console.log(uniqueElements, options);
}
var debouncedDoStuff = _debounce(doStuff, 2000); // as original.
function once(options) {
var targetList = [];
function doOnce() {
targetList.push($(this));
debouncedDoStuff(targetList, options);
// Note that again, I don't restrict the callback to a single
// event type, because the debouncing and the deduplication
// already ensure that each input is processed only once.
// This also prevents a problem that might ignore a 'keyup' event
// in one element if 'change' was already triggered in another.
}
return doOnce;
}
// The next part is the same as your original code.
$(document).ready(function(){
var options = {foo:'bar', baz:'biz'};
$('.textInputs').on('keyup.my.evt change.my.evt', once(options));
});
后一个选项可能更精简一些,因为您的闭包较少,但除非您有数百个输入元素,否则这可能并不重要。
第三种选择是使用框架以传统方式构建事件处理。Backbone是一个框架的例子,它与jQuery和Underscore配合得很好,它可以很好地处理这种情况。但是,使用框架来得心应手超出了这个答案的范围。
评论