防抖节流 JavaScript版

  • throttle节流:基于时间的频率来进行抽样更改。一个函数执行一次后,只有大于设定的执行周期后才会执行第二次。
  • debounce防抖:一段时间的不活动之后发布更改。一个需要频繁触发的函数,在规定时间内,只让最后一次生效,前面的不生效。
  • requestAnimationFrame 节流:基于requestAnimationFrame来进行抽样更改。

页面查看节流防抖区别

节流

throttle节流

利用闭包和时间戳或定时器

Note:以下第一段代码考虑了this和上下文对象,再往下的代码均不考虑,只关注防抖节流核心逻辑

// 时间戳
// 以下代码考虑了this和上下文对象,再往下的代码均不考虑,只关注防抖节流核心逻辑。
function throttle(fn, delay) {
  let lastTime = 0;
  return function (...args) {
    let nowTime = Date.now();
    if (nowTime - lastTime > delay) {
      fn().apply(this, args); 
      lastTime = nowTime;
    }
  };
}

// 定时器
function throttle(fn, delay) {
  let valid = true;
  return function (...args) {
    if (!valid) {
      return false;
    }
    valid = false;
    setTimeout(() => {
      fn();
      valid = true;
    }, delay);
  };
}

_.throttle

查看lodash官方文档

requestAnimationFrame 节流

以下内容来自于红宝书。

requestAnimationFrame一般用作动画,用以通知浏览器某些JavaScript代码要执行动画了。它接收一个参数,此参数是一个要在重绘屏幕前调用的函数,函数就是修改 DOM 样式以反映下一次重绘有什么变化的地方。

支持这个方法的浏览器会暴露出作为钩子的回调队列。这个钩子就是浏览器在执行下一次重绘之前的一个点。这个回调队列是一个可修改的函数列表,包含应该在重绘之前调用的函数。每次调用requestAnimationFrame都会在队列上推入一个回调函数,队列的长度没有限制。

其实这个回调队列的行为不一定跟动画有关。不过,通过requestAnimationFrame递归地向队列 中加入回调函数,可以保证每次重绘最多只调用一次回调函数,如下代码

function updateProgress() {
 	var div = document.getElementById("status");
 	div.style.width = (parseInt(div.style.width, 10) + 5) + "%";
 	if (div.style.left != "100%") {
 		requestAnimationFrame(updateProgress);
 	}
}
requestAnimationFrame(updateProgress); 

这是一个很棒的节流工具,如果想把函数的调用限制在每次重绘前发生,那么可以像这样下面把它封装到 requestAnimationFrame调用中:

function expensiveOperation() {
 	console.log('Invoked at', Date.now());
}
window.addEventListener('scroll', () => {
 	window.requestAnimationFrame(expensiveOperation);
});

这样会把所有回调的执行集中在重绘钩子,但不会过滤掉每次重绘的多余调用。此时,定义一个标志变量,由回调设置其开关状态,就可以将多余的调用屏蔽:

let enqueued = false;
function expensiveOperation() {
 	console.log('Invoked at', Date.now());
 	enqueued = false;
}
window.addEventListener('scroll', () => {
 	if (!enqueued) {
 		enqueued = true;
 		window.requestAnimationFrame(expensiveOperation);
 	}
});

因为重绘是非常频繁的操作,所以这还算不上真正的节流。更好的办法是配合使用一个计时器来限 制操作执行的频率。这样,计时器可以限制实际的操作执行间隔,而requestAnimationFrame控制在浏览器的哪个渲染周期中执行:

let enabled = true;
function expensiveOperation() {
 	console.log('Invoked at', Date.now());
}
window.addEventListener('scroll', () => {
 	if (enabled) {
 		enabled = false;
 		window.requestAnimationFrame(expensiveOperation);
 		window.setTimeout(() => enabled = true, 50);
 	}
}); 

防抖

debounce防抖

function debounce(fn, delay) {
  let timer = null;
  return function () {
    if (timer) {
      clearTimeout(timer);
    }
    timer = setTimeout(function () {
      fn(); 
    }, delay);
  };
}

_.debounce

查看lodash官方文档

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值