throttle.js 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243
  1. module.exports = function (func, wait, options) {
  2. /* options的默认值
  3. * 表示首次调用返回值方法时,会马上调用func;否则仅会记录当前时刻,当第二次调用的时间间隔超过wait时,才调用func。
  4. * options.leading = true;
  5. * 表示当调用方法时,未到达wait指定的时间间隔,则启动计时器延迟调用func函数,若后续在既未达到wait指定的时间间隔和func函数又未被调用的情况下调用返回值方法,则被调用请求将被丢弃。
  6. * options.trailing = true;
  7. * 注意:当options.trailing = false时,效果与上面的简单实现效果相同
  8. */
  9. var context, args, result;
  10. var timeout = null;
  11. var previous = 0;
  12. if (!options) options = {};
  13. var later = function () {
  14. previous = options.leading === false ? 0 : new Date().getTime();
  15. timeout = null;
  16. result = func.apply(context, args);
  17. if (!timeout) context = args = null;
  18. };
  19. return function () {
  20. var now = new Date().getTime();
  21. if (!previous && options.leading === false) previous = now;
  22. // 计算剩余时间
  23. var remaining = wait - (now - previous);
  24. context = this;
  25. args = arguments;
  26. // 当到达wait指定的时间间隔,则调用func函数
  27. // 精彩之处:按理来说remaining <= 0已经足够证明已经到达wait的时间间隔,但这里还考虑到假如客户端修改了系统时间则马上执行func函数。
  28. if (remaining <= 0 || remaining > wait) {
  29. // 由于setTimeout存在最小时间精度问题,因此会存在到达wait的时间间隔,但之前设置的setTimeout操作还没被执行,因此为保险起见,这里先清理setTimeout操作
  30. if (timeout) {
  31. clearTimeout(timeout);
  32. timeout = null;
  33. }
  34. previous = now;
  35. result = func.apply(context, args);
  36. if (!timeout) context = args = null;
  37. } else if (!timeout && options.trailing !== false) {
  38. // options.trailing=true时,延时执行func函数
  39. timeout = setTimeout(later, remaining);
  40. }
  41. return result;
  42. };
  43. };