【问题标题】:Delayed callback function on slide event幻灯片事件的延迟回调函数
【发布时间】:2016-05-31 03:16:06
【问题描述】:

我正在使用 jqueryui 的滑块小部件。
我希望在滑块的滑动事件上运行一个函数,但我只希望它在(700 毫秒)延迟后运行。如果滑块手柄继续移动(即再次触发滑动),那么我希望延迟超时重置。

我尝试使用 jquery 的 doTimeout 和 setTimeout 均无济于事。我所做的任何事情似乎都可以防止滑块手柄改变位置。

var heavy = {
    updatesomething: function() {
        //some computationally heavy code
    }
}

$('#slider').slider({
    min:1, max:99, orientation: 'vertical',
    slide: function(event, ui) {
        $(this).doTimeout('timeoutid', 700, function() {
            heavy.updatesomething(this, ui.value);  });
    }
});

【问题讨论】:

    标签: jquery jquery-ui timeout delay jquery-ui-slider


    【解决方案1】:

    使用现有的去抖动实现。下面的例子取自davidwalsh blog。此外,您无需传递上下文,而是使用apply 如下所示调用具有正确上下文和参数的函数。

    var heavy = {
      updatesomething: function(event, ui) {
        console.log(this);
        console.log(ui);
      }
    }
    
    // taken from https://davidwalsh.name/javascript-debounce-function
    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);
      };
    };
    
    $('#slider').slider({
      min: 1,
      max: 99,
      orientation: 'vertical',
      slide: debounce(function(event, ui) {
        heavy.updatesomething.apply(this, arguments);
        //---------------------------^-context  ^-- what it says
      }, 700)
    });
    <link href="//code.jquery.com/ui/1.11.4/themes/ui-lightness/jquery-ui.css" rel="stylesheet" />
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
    <div id="slider"></div>

    【讨论】:

      【解决方案2】:

      在这种情况下,去抖动的问题是,如果用户不断移动滑块,则不会有任何事件。所以使用节流更有用。

      下面的示例还包括完整的 lodash Throttle 和 Debounce

      'use strict';
      
      /**
       * Creates a debounced function that delays invoking `func` until after `wait`
       * milliseconds have elapsed since the last time the debounced function was
       * invoked. The debounced function comes with a `cancel` method to cancel
       * delayed `func` invocations and a `flush` method to immediately invoke them.
       * Provide `options` to indicate whether `func` should be invoked on the
       * leading and/or trailing edge of the `wait` timeout. The `func` is invoked
       * with the last arguments provided to the debounced function. Subsequent
       * calls to the debounced function return the result of the last `func`
       * invocation.
       *
       * **Note:** If `leading` and `trailing` options are `true`, `func` is
       * invoked on the trailing edge of the timeout only if the debounced function
       * is invoked more than once during the `wait` timeout.
       *
       * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
       * until to the next tick, similar to `setTimeout` with a timeout of `0`.
       *
       * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
       * for details over the differences between `_.debounce` and `_.throttle`.
       *
       * from lodash - https://github.com/lodash/lodash/blob/4.16.2/lodash.js#L10218
       */
      function debounce(func, wait, options) {
      	if (!options) options = {};
      
      	let lastArgs, lastThis, maxWait, result, timerId, lastCallTime, lastInvokeTime = 0,
      		leading = false,
      		maxing = false,
      		trailing = true;
      
      	wait = wait || 0;
      	leading = !!options.leading;
      	maxing = 'maxWait' in options;
      	maxWait = maxing ? Math.max(options.maxWait || 0, wait) : maxWait;
      	trailing = 'trailing' in options ? !!options.trailing : trailing;
      
      	function invokeFunc(time) {
      		const args = lastArgs,
      			thisArg = lastThis;
      
      		lastArgs = lastThis = undefined;
      		lastInvokeTime = time;
      		result = func.apply(thisArg, args);
      		return result;
      	}
      
      	function leadingEdge(time) {
      		// Reset any `maxWait` timer.
      		lastInvokeTime = time;
      		// Start the timer for the trailing edge.
      		timerId = setTimeout(timerExpired, wait);
      		// Invoke the leading edge.
      		return leading ? invokeFunc(time) : result;
      	}
      
      	function remainingWait(time) {
      		const timeSinceLastCall = time - lastCallTime,
      			timeSinceLastInvoke = time - lastInvokeTime,
      			result = wait - timeSinceLastCall;
      
      		return maxing ? Math.min(result, maxWait - timeSinceLastInvoke) : result;
      	}
      
      	function shouldInvoke(time) {
      		const timeSinceLastCall = time - lastCallTime,
      			timeSinceLastInvoke = time - lastInvokeTime;
      
      		// Either this is the first call, activity has stopped and we're at the
      		// trailing edge, the system time has gone backwards and we're treating
      		// it as the trailing edge, or we've hit the `maxWait` limit.
      		return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||
      			(timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));
      	}
      
      	function timerExpired() {
      		const time = Date.now();
      		if (shouldInvoke(time)) {
      			return trailingEdge(time);
      		}
      		// Restart the timer.
      		timerId = setTimeout(timerExpired, remainingWait(time));
      	}
      
      	function trailingEdge(time) {
      		timerId = undefined;
      
      		// Only invoke if we have `lastArgs` which means `func` has been
      		// debounced at least once.
      		if (trailing && lastArgs) {
      			return invokeFunc(time);
      		}
      		lastArgs = lastThis = undefined;
      		return result;
      	}
      
      	function cancel() {
      		if (timerId !== undefined) {
      			clearTimeout(timerId);
      		}
      		lastInvokeTime = 0;
      		lastArgs = lastCallTime = lastThis = timerId = undefined;
      	}
      
      	function flush() {
      		return timerId === undefined ? result : trailingEdge(Date.now());
      	}
      
      	function debounced(...args) {
      		const time = Date.now(),
      			isInvoking = shouldInvoke(time);
      
      		lastArgs = args;
      		lastThis = this;
      		lastCallTime = time;
      
      		if (isInvoking) {
      			if (timerId === undefined) {
      				return leadingEdge(lastCallTime);
      			}
      			if (maxing) {
      				// Handle invocations in a tight loop.
      				timerId = setTimeout(timerExpired, wait);
      				return invokeFunc(lastCallTime);
      			}
      		}
      		if (timerId === undefined) {
      			timerId = setTimeout(timerExpired, wait);
      		}
      		return result;
      	}
      	debounced.cancel = cancel;
      	debounced.flush = flush;
      	return debounced;
      }
      
      /**
       * Creates a throttled function that only invokes `func` at most once per
       * every `wait` milliseconds. The throttled function comes with a `cancel`
       * method to cancel delayed `func` invocations and a `flush` method to
       * immediately invoke them. Provide `options` to indicate whether `func`
       * should be invoked on the leading and/or trailing edge of the `wait`
       * timeout. The `func` is invoked with the last arguments provided to the
       * throttled function. Subsequent calls to the throttled function return the
       * result of the last `func` invocation.
       *
       * **Note:** If `leading` and `trailing` options are `true`, `func` is
       * invoked on the trailing edge of the timeout only if the throttled function
       * is invoked more than once during the `wait` timeout.
       *
       * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
       * until to the next tick, similar to `setTimeout` with a timeout of `0`.
       *
       * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
       * for details over the differences between `_.throttle` and `_.debounce`.
       */
      function throttle(func, wait, options) {
      	if (!options) options = {};
      	let leading = true,
      		trailing = true;
      
      	leading = 'leading' in options ? !!options.leading : leading;
      	trailing = 'trailing' in options ? !!options.trailing : trailing;
      
      	return debounce(func, wait, {
      		'leading': leading,
      		'maxWait': wait,
      		'trailing': trailing
      	});
      }
      
      
      let counter=0;
      
      $('#slider').slider({
        min: 1,
        max: 99,
        orientation: 'vertical',
        slide: throttle(function(event, ui) {
          $(event.target).slider('option', 'value', ui.value); // making sure value is correct
          console.log(ui.value);
        }, 100)
      });
      <link href="//code.jquery.com/ui/1.11.4/themes/ui-lightness/jquery-ui.css" rel="stylesheet" />
      <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
      <script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
      <div id="slider"></div>

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-08-15
        • 1970-01-01
        • 1970-01-01
        • 2012-12-20
        • 1970-01-01
        • 2019-07-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多