web-dev-qa-db-ja.com

lodashデバウンスが匿名関数で機能しない

こんにちは、キーアップイベントに直接渡されたときにデバウンス機能が期待どおりに機能する理由を理解できないようです。しかし、匿名関数内にラップすると機能しません。

私は問題のフィドルを持っています: http://jsfiddle.net/6hg95/1/

編集:私が試したすべてのものを追加しました。

[〜#〜] html [〜#〜]

<input id='anonFunction'/>
<input id='noReturnAnonFunction'/>
<input id='exeDebouncedFunc'/>
<input id='function'/>
<div id='output'></div>

[〜#〜] javascript [〜#〜]

$(document).ready(function(){
    $('#anonFunction').on('keyup', function () {
        return _.debounce(debounceIt, 500, false); //Why does this differ from #function
    });
    $('#noReturnAnonFunction').on('keyup', function () {
        _.debounce(debounceIt, 500, false); //Not being executed
    });
    $('#exeDebouncedFunc').on('keyup', function () {
        _.debounce(debounceIt, 500, false)(); //Executing the debounced function results in wrong behaviour
    });
    $('#function').on('keyup', _.debounce(debounceIt, 500, false)); //This is working.
});

function debounceIt(){
    $('#output').append('debounced');
}

anonFunctionおよびnoReturnAnonFunctionはデバウンス機能を起動しません。しかし、最後のfunctionが起動します。これがなぜなのか分かりません。誰でもこれを理解するのを手伝ってもらえますか?

[〜#〜] edit [〜#〜]わかりました。したがって、#exeDebouncedFunc(参照するもの)でデバウンスが発生しない理由は関数は匿名関数のスコープで実行され、別のキーアップイベントが別の匿名スコープで新しい関数を作成するため。したがって、デバウンスされた関数を何回か入力するたびに発動します(予想される動作である1回の発火の代わりに、#functionの発動を参照)?

#anonFunction#functionの違いを説明してください。これは、それらの一方が機能し、もう一方が機能しない理由を再度検討する問題ですか?

[〜#〜] edit [〜#〜]わかりました。それで、なぜこれが起こっているのか理解できました。そして、ここに私が無名関数の中にそれをラップする必要がある理由があります:

フィドル: http://jsfiddle.net/6hg95/5/

[〜#〜] html [〜#〜]

<input id='anonFunction'/>
<div id='output'></div>

[〜#〜] javascript [〜#〜]

(function(){
    var debounce = _.debounce(fireServerEvent, 500, false);

    $('#anonFunction').on('keyup', function () {
        //clear textfield
        $('#output').append('clearNotifications<br/>');
        debounce();
    });

    function fireServerEvent(){
        $('#output').append('serverEvent<br/>');
    }
})();
47

パルパティムが説明したように、その理由は_.debouce(...)が関数を返すという事実にあり、呼び出されたときにそれは魔法です。

したがって、_#anonFunction_の例では、キーリスナーがあり、呼び出されると、呼び出し側に関数を返すだけで、呼び出し側はイベントリスナーからの戻り値に対して何も行いません。

これは_.debounce(...)定義のスニペットです:

__.debounce
function (func, wait, immediate) {
    var timeout;
    return function() {
      var context = this, args = arguments;
      var later = function() {
        timeout = null;
        if (!immediate) func.apply(context, args);
      };
      if (immediate && !timeout) func.apply(context, args);
      clearTimeout(timeout);
      timeout = setTimeout(later, wait);
    };
  } 
_

キーイベントリスナーは、_.debounce(...)から返された関数を呼び出す必要があります。または、匿名でない例のように、_.debounce(...)呼び出しから返された関数をイベントリスナーとして使用できます。

51
Michael Dahl

debounce は関数を実行せず、デバウンス性が組み込まれた関数を返します。

戻り値

(Function):デバウンスされた新しい関数を返します。

したがって、#functionハンドラーは、jQueryがキーアップハンドラーとして使用する関数を返すことで、実際に正しいことを実行しています。 #noReturnAnonFunctionの例を修正するには、関数のコンテキストでデバウンスされた関数を実行するだけです。

$('#noReturnAnonFunction').on('keyup', function () {
    _.debounce(debounceIt, 500, false)(); // Immediately executes
});

しかし、それはデバウンスの周りに不必要な匿名関数ラッパーを導入しています。

37
Palpatim

簡単に考える

_.debounceはデバウンスされた関数を返します!そのため、

$el.on('keyup'), function(){
   _.debounce(doYourThing,500); //uh I want to debounce this
}

代わりに、デバウンスされた関数を呼び出します

var doYourThingDebounced = _.debounce(doYourThing, 500); //YES, this will always be debounced

$el.on('keyup', doYourThingDebounced);
30
zevero

次のようなデバウンス関数を返すことができます。

(function(){
    var debounce = _.debounce(fireServerEvent, 500, false);

    $('#anonFunction').on('keyup', function () {
        //clear textfield
        $('#output').append('clearNotifications<br/>');
        return debounce();
    });

    function fireServerEvent(){
        $('#output').append('serverEvent<br/>');
    }
})();
6
jiv-e

より一般的には、末尾の振る舞い(ラストクリックのアカウント、または選択入力での最後の変更の可能性が高い)でのデバウンスと、最初のクリック/変更に関する視覚的なフィードバックが必要な場合、同じ問題に直面します。

これは動作しません:

$(document).on('change', "#select", function() {
    $('.ajax-loader').show();
    _.debounce(processSelectChange, 1000);
});

これは解決策になります:

$(document).on('change', "#select", function() {
    $('.ajax-loader').show();
});
$(document).on('change', "#select", _.debounce(processSelectChange, 1000));
0
Baishu