-
Notifications
You must be signed in to change notification settings - Fork 3.3k
Open
Labels
Description
- 防抖
触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间
- 思路:
每次触发事件时都取消之前的延时调用方法
function debounce(fn) {
let timeout = null; // 创建一个标记用来存放定时器的返回值
return function () {
clearTimeout(timeout); // 每当用户输入的时候把前一个 setTimeout clear 掉
timeout = setTimeout(() => { // 然后又创建一个新的 setTimeout, 这样就能保证输入字符后的 interval 间隔内如果还有字符输入的话,就不会执行 fn 函数
fn.apply(this, arguments);
}, 500);
};
}
function sayHi() {
console.log('防抖成功');
}
var inp = document.getElementById('inp');
inp.addEventListener('input', debounce(sayHi)); // 防抖
- 节流
高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率
- 思路:
每次触发事件时都判断当前是否有等待执行的延时函数
function throttle(fn) {
let canRun = true; // 通过闭包保存一个标记
return function () {
if (!canRun) return; // 在函数开头判断标记是否为true,不为true则return
canRun = false; // 立即设置为false
setTimeout(() => { // 将外部传入的函数的执行放在setTimeout中
fn.apply(this, arguments);
// 最后在setTimeout执行完毕后再把标记设置为true(关键)表示可以执行下一次循环了。当定时器没有执行的时候标记永远是false,在开头被return掉
canRun = true;
}, 500);
};
}
function sayHi(e) {
console.log(e.target.innerWidth, e.target.innerHeight);
}
window.addEventListener('resize', throttle(sayHi));
xiliangzhou6216, webzhaochong, xingorg1, machangzhi, KChrisZhang and 381 moremlanfe, viprespro, yaoyuanrong, daidaiisagirl and Anber-Hkeeperererer, DillionZ, tazu3927, zyl0096, slbapp and 34 moreazl397985856, zy0228, thinkfish, JuneScut, nanfs and 38 morepandaSpace, szdbb1102, crown-li, Mwangzhi, xxweii and 28 morexiaobutiaoer, zy0228, shoushou70, thinkfish, JuneScut and 39 morethinkfish, lllwangwenlong, JuneScut, LYN-alan, Reaper622 and 42 moreJaceSetry, tazu3927, szdbb1102, xiaofeiMophsic, genwohuijia and 43 more
Metadata
Metadata
Assignees
Labels
Type
Projects
Milestone
Relationships
Development
Select code repository
Activity
[-]节流和防抖的个人见解[/-][+]第三题:节流和防抖的个人见解[/+]Carrie999 commentedon Feb 14, 2019
请问,为什么要 fn.apply(this, arguments);而不是这样 fn()
barbara012 commentedon Feb 18, 2019
@Carrie999 关键在第一个参数,为了确保上下文环境为当前的this,所以不能直接用fn。
MinosIE commentedon Feb 18, 2019
@Carrie999 call 和 apply 可以了解一下
yangtao2o commentedon Feb 18, 2019
之前有看过一步步实现的文章,如下:
zhongtingbing commentedon Feb 18, 2019
请问为甚么你要确保fn执行的上下文是this?在这个箭头函数里this又是指向的谁?
lilywang711 commentedon Feb 18, 2019
@zhongtingbing
加上 apply 确保 在 sayHi 函数里的 this 指向的是 input对象(不然就指向 window 了,不是我们想要的)。
这里的箭头函数依旧是指向 input 对象。
lilywang711 commentedon Feb 18, 2019
@zhongtingbing 你去试试在 不加 apply 时去 sayHi 函数里打印下 this看看什么
是指向window的。因为 sayHi 函数是在全局中调用运行,所以 this 指向了 window,所以才需要加上 apply,显示绑定 this 值(input对象)到 sayH 函数里面去
yishuihan-001 commentedon Feb 19, 2019
@Carrie999 为了保证sayHi执行时的this指向input
Crazy404 commentedon Feb 19, 2019
请问防抖那里可以写成
setTimeout(fn.bind(this), 500)
吗(小白的疑问)
Mathround commentedon Feb 20, 2019
估计是改变this指向
fan-2 commentedon Feb 20, 2019
Yolo-0317 commentedon Feb 20, 2019
这里用了apply确实使得this指向了input对象;对于“因为 sayHi 函数定义在全局中,所以调用时里面this指向window”,测试了一下直接使用fn(arguments)的话,在sayHi中打印this为undefined;js中this是在运行时绑定的,而不是定义时绑定的
Liubasara commentedon Feb 21, 2019
有个问题,假如传入的方法是异步的,上述的节流方法是没用的啊,考虑把
fn.apply(this, arguments)
这一句放在setTimeout外面是不是会好一点?就像下面这样。116 remaining items
FansOne commentedon Mar 26, 2021
zhuzhile commentedon Apr 14, 2021
说的太笼统了,setTimeout的this指的是window,而箭头函数指的不是setTimeout的this是function的this,都是window对象,所以这个apply没有什么意思。
Yrobot commentedon Apr 21, 2021
用箭头函数的目的是为了让fn.apply的this和arguments都是闭包return的函数的this和arguments。
下面应该是常用场景的代码,可以参考这个代码思考实现
Yrobot commentedon Apr 21, 2021
其实对于节流我有个疑问,最后一次回调是否应该必须触发。
当前的实现可能存在最后一次不触发的情况。
假设 time 是相对于第一次触发的时间差
理想情况(eventloop不拥挤)fn执行时间节点为:500(0)、1200(700)
最后一次1000的没有触发
Yrobot commentedon Apr 21, 2021
我优化了一下节流的逻辑,保证最后一次必须执行。
理想情况(eventloop 不拥挤)fn 执行时间节点为:500(0)、1200(700)、1500[1000]
lzxjack commentedon Jun 18, 2021
1. 手写防抖函数(debounce)
防抖函数功能:
比如一个搜索框,应用防抖函数后,当用户不断输入内容时,不会发送请求。只有当用户一段时间
T
内不输入内容了,才会发送一次请求。如果小于这段时间T
继续输入内容的话,就会重新计算时间T
,也不会发送请求。这样降低了发送请求的次数,提高性能的同时也提升了用户体验。实现防抖函数:
实现效果:
上方输入框,下方显示区,不断输入内容时,下方显示区不会更新。只有在
1s
内不输入内容了,下方显示区才会更新内容。2. 手写节流函数(throttle)
节流函数功能:
实现节流函数:
实现效果:
上方输入框,下方显示区。不断输入内容时,每隔
500ms
,下方显示区才会更新一次内容。zhengyongkai commentedon Jul 6, 2021
我感觉节流应该是用在滚动条 防抖用在输入框 突然觉得防抖这个词有点可以理解为百度输入查询时候下面那个查询弹出框为了不然他一直抖动....
Ha0ran2001 commentedon Aug 31, 2021
Ha0ran2001 commentedon Oct 27, 2021
@Carrie999 https://medium.com/@griffinmichl/implementing-debounce-in-javascript-eab51a12311e看这个,外国人喜欢循序渐进
wangziqi0503 commentedon Mar 21, 2022
Yangfan2016 commentedon Aug 3, 2022
防抖 一定时间内触发的事件合成一个事件进行触发 ,常用于 搜索框的输入联想提示 功能
截流 一定时间内触发的事件 按 一定时间规律性的触发,常用于 无限滚动加载
xiaogu-123 commentedon Nov 22, 2022
我用 vue 试了一下,请大佬们指点:
防抖
节流