为了账号安全,请及时绑定邮箱和手机立即绑定

有人可以解释Javascript中的“去抖动”功能

有人可以解释Javascript中的“去抖动”功能

暮色呼如 2019-10-12 18:07:14
有人可以解释Javascript中的“去抖动”功能我对javascript中的“debouncing”函数很感兴趣,这里写的:http://davidwalsh.name/javascript-debounce-function不幸的是,代码没有清楚地解释清楚,以便我理解。任何人都可以帮我弄清楚它是如何工作的(我在下面留下了我的评论)。总之,我真的不明白这是如何工作的   // Returns a function, that, as long as it continues to be invoked, will not    // be triggered. The function will be called after it stops being called for    // N milliseconds.function debounce(func, wait, immediate) {     var timeout;     return function() {         var context = this, args = arguments;         var later = function() {             timeout = null;             if (!immediate) func.apply(context, args);         };         var callNow = immediate && !timeout;         clearTimeout(timeout);         timeout = setTimeout(later, wait);         if (callNow) func.apply(context, args);     };};编辑:复制的代码片段之前有callNow错误的位置。
查看完整描述

3 回答

?
慕哥9229398

TA贡献1877条经验 获得超6个赞

问题中的代码稍微改变了链接中的代码。在链接中,检查是否(immediate && !timeout)在创建新的timout之前。拥有它后立即模式永远不会开火。我已经更新了我的答案,以便从链接中注释工作版本。

function debounce(func, wait, immediate) {
  // 'private' variable for instance
  // The returned function will be able to reference this due to closure.
  // Each call to the returned function will share this common timer.
  var timeout;

  // Calling debounce returns a new anonymous function
  return function() {
    // reference the context and args for the setTimeout function
    var context = this,
      args = arguments;

    // Should the function be called now? If immediate is true
    //   and not already in a timeout then the answer is: Yes
    var callNow = immediate && !timeout;

    // This is the basic debounce behaviour where you can call this 
    //   function several times, but it will only execute once 
    //   [before or after imposing a delay]. 
    //   Each time the returned function is called, the timer starts over.
    clearTimeout(timeout);

    // Set the new timeout
    timeout = setTimeout(function() {

      // Inside the timeout function, clear the timeout variable
      // which will let the next execution run when in 'immediate' mode
      timeout = null;

      // Check if the function already ran with the immediate flag
      if (!immediate) {
        // Call the original function with apply
        // apply lets you define the 'this' object as well as the arguments 
        //    (both captured before setTimeout)
        func.apply(context, args);
      }
    }, wait);

    // Immediate mode and no wait timer? Execute the function..
    if (callNow) func.apply(context, args);
  }}/////////////////////////////////// DEMO:function onMouseMove(e){
  console.clear();
  console.log(e.x, e.y);}// Define the debounced functionvar debouncedMouseMove = debounce(onMouseMove, 50);// Call the debounced function on every mouse movewindow.addEventListener('mousemove', debouncedMouseMove);



查看完整回答
反对 回复 2019-10-13
?
杨魅力

TA贡献1811条经验 获得超5个赞

这里要注意的重要一点是debounce产生一个“关闭” 变量的函数timeouttimeout在生成函数的每次调用期间,即使在debounce返回之后,变量仍然可以访问,并且可以在不同的调用之间进行切换。

总体思路debounce如下:

  1. 没有超时开始。

  2. 如果调用生成的函数,则清除并重置超时。

  3. 如果超时,请调用原始函数。

第一点是var timeout;,它确实是公正的undefined。幸运的是,clearTimeout它的输入相当松散:传递一个undefined计时器标识符会导致它什么也不做,它不会抛出错误或其他东西。

第二点由生成的函数完成。它首先在变量中存储有关调用的一些信息(this上下文和arguments),以便稍后可以将它们用于去抖动调用。然后它清除超时(如果有一组),然后创建一个新的替换它使用setTimeout请注意,这会覆盖timeout多个函数调用的值,并且该值会持续存在!这允许去抖动实际工作:如果多次调用该函数,timeout则使用新的计时器多次覆盖。如果不是这种情况,多次呼叫将导致启动多个定时器,这些定时器保持活动状态 - 呼叫只会被延迟,但不会被去抖动。

第三点是在超时回调中完成的。它取消设置timeout变量并使用存储的调用信息进行实际的函数调用。

immediate标志应该控制是否应该在定时器之前之后调用该函数。如果是false,则直到计时器被命中后才调用原始函数。如果是true,则首先调用原始函数,并且在计时器被命中之前不再调用它。

但是,我确实认为if (immediate && !timeout)检查错误:timeout刚刚设置为返回的计时器标识符,setTimeout因此!timeout始终false在该点,因此永远不能调用该函数。当前版本的underscore.js似乎有一个稍微不同的检查,它immediate && !timeout 调用之前进行评估setTimeout。(算法也有点不同,例如它不使用clearTimeout。)这就是为什么你应该总是尝试使用最新版本的库。:-)



查看完整回答
反对 回复 2019-10-13
?
慕斯709654

TA贡献1840条经验 获得超5个赞

去抖动函数在调用时不会执行,它们会在执行前等待一段可配置的持续时间暂停调用; 每次新调用都会重新启动计时器。

限制函数执行,然后等待可配置的持续时间,然后再次触发。

去抖动非常适合按键事件; 当用户开始输入然后暂停时,您将所有按键提交为单个事件,从而减少处理调用。

对于您只希望允许用户在设定的一段时间内调用一次的实时端点,Throttle非常适合。

查看Underscore.js的实现。



查看完整回答
反对 回复 2019-10-13
  • 3 回答
  • 0 关注
  • 393 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信