簡體   English   中英

在閉包中使用下划線去抖動函數

[英]Using underscore debounce function inside closure

我使用閉包來確保僅對綁定到元素的眾多事件之一進行操作,例如: $('.textInputs').on('keyup.my.evt change.my.evt', once(options));

我在once函數閉包中使用下划線的_.debounce 如果我在一個輸入中進行更改並在更改另一個輸入之前等待,一切都會正常。 如果我對一個輸入進行更改並快速切換到下一個輸入,並在第一個輸入的時間等待到期之前的一秒鍾內進行更改,則僅對第二個輸入執行去抖動函數。 這告訴我兩個輸入都使用從 debounce 返回的相同函數,但我不確定如何更改我的代碼結構,以便每個輸入使用自己的 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,一次用於更改)而我使用一次閉包的方式該函數只是為這兩個事件執行一次。

您可以通過傳遞_.debounce創建doStuff的去抖動版本。 你的問題是你只做一次,所以只有一個這樣的去抖動版本,事件處理程序必須在所有元素之間共享。 去抖動意味着只有一些調用才能真正到達原始函數。 從本質上講,您隱藏了除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 配合使用的框架示例,它可以很好地處理這種情況。 但是,使用框架超出了這個答案的范圍。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM