1. 什么是防抖节流
- 防抖就是无论如何触发事件,只在设定的n秒之后执行时间,如果在n秒内再次触发了事件,则重新计时
- 节流就是在设定的时间内只触发一次
2. 区别
- 防抖以最后一次触发为准,如果在设定的n秒内再次触发,则以新的事件时间为准
- 节流以第一次触发为准,执行第一次时间后,在设定的n秒内触发都不会执行
3. 如何实现
// 下面的代码共用此绑定事件
function doSomething() {
console.log('input')
}
var input = document.getElementById('input')
// 防抖
input.oninput = throttle(doSomething, 5000, {
leading: false
})
// 节流
input.oninput = throttle(doSomething, 5000, {
leading: false
})
防抖
- 利用定时器
- 思路:
- 如果在设定的时间内触发,清除定时器重新计时
- 重新设定定时器,利用apply/call执行函数
- 可以增加立刻执行选项
function debounce(func, wait, immediate) {
var timeout, result;
return function () {
var context = this; // 解决event指向问题
var args = arguments; // 传参
if (timeout) clearTimeout(timeout);
if (immediate) {
// 如果已经执行过,不再执行
var callNow = !timeout;
timeout = setTimeout(function(){
timeout = null;
}, wait)
if (callNow) result = func.apply(context, args) // 只有立刻执行有返回值,使用settimeout执行函数,因为异步原因,result为undefined
} else { // 非立刻执行保持原逻辑
timeout = setTimeout(function(){
func.apply(context, args)
}, wait);
}
return result;
}
}
节流
- 利用定时器或时间戳
- 总结:
- 时间戳方式:第一次进入立刻执行;定时器:并不立刻执行,在n秒之后执行
- 时间戳:停止触发了,就不执行了,因为是根据触发的时间去和上一次时间进行比较;定时器:停止触发了,仍然会执行
- 思路:
- 结合两种方式的优点,既能立刻执行,停止触发也能执行最后一次
- 分两种判断逻辑:1. 时间戳 2. 定时器;定时器为空(第一次进入或定时器执行完成后)时进入时间戳逻辑;其余是进入定时器逻辑
function throttle(fn, wait, options) {
var timeout = null, pre = 0;
var context,arg;
if (!options) options = {};
var throttled = function () {
context = this;
arg = arguments;
var now = +new Date();
if (!pre && options.leading === false) pre = now; // +++ 禁止立刻执行,remaining > 0, 执行定时器逻辑
var remaining = wait - (now - pre); // 计算还剩下多少时间执行下一次方法
// 时间戳:立刻执行,第一次进入remaining必小于0,因为wait-now
if (remaining <= 0) {
console.log('时间戳')
if (timeout) {
clearTimeout(timeout) // 第一次进入,清除定时器,为后面做准备
timeout = null
}
pre = now; // now时间赋值pre,频繁触发时,基本不会出现remaining <= 0,会走下面的逻辑
fn.apply(context, arg)
if (!timeout) context = arg = null; // +++ 不太明白,或许是手动清除内存?
} else if (!timeout && options.trailing !== false) { // +++ 增加options.trailing !== false判断,停止触发不设置定时器了
console.log('定时器')
timeout = setTimeout(function () {
pre = options.leading === false ? 0 : +new Date(); // +++ 如果需要禁止立刻执行,需要重新将pre重置为0,避免进入时间戳逻辑
timeout = null;
fn.apply(context, arg)
if (!timeout) context = arg = null; // +++ 不太明白,或许是手动清除内存?
}, remaining)
}
}
throttled.cancel = function () {
clearTimeout(timeout)
pre = 0;
timeout = null
}
return throttled;
}
参考链接
- 防抖
- 节流
最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。