在闭包中使用下划线反跳函数



我使用闭包来确保只对绑定到元素的许多事件中的一个执行操作,例如:$('.textInputs').on('keyup.my.evt change.my.evt', once(options));

我在once函数闭包中使用下划线的_.debounce。如果我在一个输入中进行更改,并在更改另一个输入之前等待,一切都会正常工作。如果我在一个输入中进行了更改,并快速切换到下一个输入,并在第一个输入的时间等待到期之前在第二个输入中做出更改,则只对第二个输出执行去抖动功能。这告诉我,两个输入使用的是从去跳动返回的相同函数,但我不确定如何更改我的代码结构,使每个输入使用自己的去跳动函数。

去抖动功能:

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,一次用于change(,而我使用once闭包的方式是,对于这两个事件,函数只执行一次。

通过_.debounce创建doStuff的去抖动版本。您的问题是,您只执行一次,因此只有一个这样的反跳版本,事件处理程序必须在所有元素之间共享。Deboancing意味着只有一些调用真正通过原始函数。从本质上讲,除了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和Undercore配合良好的框架示例,它可以很好地处理这种情况。不过,使用框架已经超出了这个答案的范围。

最新更新