javascript 函数节流 throttle 解决函数被频繁调用、浏览器卡顿的问题

* 使用setTimeout

index.html



	
	throttle


	

函数节流 解决函数被频繁调用、浏览器卡顿的问题

  

js/throttle.js

// 函数节流 解决函数被频繁调用、浏览器卡顿的问题
var throttle = function(fn, interval) {
	var __self = fn,       // 保存需要被延迟执行的函数引用
		timer,             // 定时器
		firstTime = true;  // 是否第1次被调用
	return function() {
		var args = arguments, __me = this;

		// 如果第1次被调用, 不需要延迟执行
		if (firstTime) {
			__self.apply(__me, args);
			return firstTime = false;
		}
		// 如果定时器还在, 说明前一次延迟执行还没有完成
		if (timer) {
			return false;
		}
		// 延迟一段时间执行
		timer = setTimeout(function() {
			clearTimeout(timer);
			timer = null;
			__self.apply(__me, args);
		}, interval || 500);
	}
}

var dom = document.createElement("h1");
dom.innerHTML = 0;
document.body.appendChild(dom);

window.onresize = throttle(function() {
	var n = parseInt(dom.innerHTML);
	dom.innerHTML = ++n;
}, 500);

  

Run:

php -S 0.0.0.0:9000

调整浏览器窗口大小

javascript 函数节流 throttle 解决函数被频繁调用、浏览器卡顿的问题_第1张图片

 

使用underscore的throttle
var _ = _ || {};

_.now = function(){
	return (new Date()).getTime();
};
_.debounce = function(func, wait, immediate) {
    // immediate默认为false
    var timeout, args, context, timestamp, result;
    var later = function() {
      // 当wait指定的时间间隔期间多次调用_.debounce返回的函数,则会不断更新timestamp的值,导致last < wait && last >= 0一直为true,从而不断启动新的计时器延时执行func
      var last = _.now() - timestamp;
      if (last < wait && last >= 0) {
        timeout = setTimeout(later, wait - last);
      } else {
        timeout = null;
        if (!immediate) {
          result = func.apply(context, args);
          if (!timeout) context = args = null;
        }
      }
    };
    return function() {
      context = this;
      args = arguments;
      timestamp = _.now();
      // 第一次调用该方法时,且immediate为true,则调用func函数
      var callNow = immediate && !timeout;
      // 在wait指定的时间间隔内首次调用该方法,则启动计时器定时调用func函数
      if (!timeout) timeout = setTimeout(later, wait);
      if (callNow) {
        result = func.apply(context, args);
        context = args = null;
      }
      return result;
    };
  };

_.throttle = function(func, wait, options) {
    /* options的默认值
     *  表示首次调用返回值方法时,会马上调用func;否则仅会记录当前时刻,当第二次调用的时间间隔超过wait时,才调用func。
     *  options.leading = true;
     * 表示当调用方法时,未到达wait指定的时间间隔,则启动计时器延迟调用func函数,若后续在既未达到wait指定的时间间隔和func函数又未被调用的情况下调用返回值方法,则被调用请求将被丢弃。
     *  options.trailing = true; 
     * 注意:当options.trailing = false时,效果与上面的简单实现效果相同
     */
    var context, args, result;
    var timeout = null;
    var previous = 0;
    if (!options) options = {};
    var later = function() {
      previous = options.leading === false ? 0 : _.now();
      timeout = null;
      result = func.apply(context, args);
      if (!timeout) context = args = null;
    };
    return function() {
      var now = _.now();
      if (!previous && options.leading === false) previous = now;
      // 计算剩余时间
      var remaining = wait - (now - previous);
      context = this;
      args = arguments;
      // 当到达wait指定的时间间隔,则调用func函数
      // 精彩之处:按理来说remaining <= 0已经足够证明已经到达wait的时间间隔,但这里还考虑到假如客户端修改了系统时间则马上执行func函数。
      if (remaining <= 0 || remaining > wait) {
        // 由于setTimeout存在最小时间精度问题,因此会存在到达wait的时间间隔,但之前设置的setTimeout操作还没被执行,因此为保险起见,这里先清理setTimeout操作
        if (timeout) {
          clearTimeout(timeout);
          timeout = null;
        }
        previous = now;
        result = func.apply(context, args);
        if (!timeout) context = args = null;
      } else if (!timeout && options.trailing !== false) {
        // options.trailing=true时,延时执行func函数
        timeout = setTimeout(later, remaining);
      }
      return result;
    };
  };

 

调用
window.onresize = _.throttle(function() {
// window.onresize = function() {
    var n = parseInt(dom.innerHTML);
    dom.innerHTML = ++n;
}, 500);
// }

 

 
关联文章:  javascript 分时函数防止大批量列表加载页面卡死
 
 
 

你可能感兴趣的:(javascript)