节流和防抖
节流(throttle)和防抖(debounce)不是js语法层面的概念,也不属于特定属于js这门语言。它其实一个工程优化的自然产物。
它们的本质是:用来对函数的调用做降频(降低单位时间内被调用的次数)处理。
在js的语境,可以抽象一下:当一个函数被以较高的频率调用时(在极短的时间内被调用了多次),出于某些原因的考虑,我们希望降低它实际被执行的频率。
这个限制的策略有两种:防抖(debounce) , 节流(throttle)
为什么要降频
一个原因:性能优化。
举个例子:在实现鼠标跟随效果时,要给mousemove添加事件监听函数,假设伪代码如下:
const fn = () => { console.log(Date.now(),'鼠标移动了,我就执行')}
dom.addEventListener('mousemove',fn)
复制代码
当鼠标移动时,fn这个函数就会以一个非常高的频率(本机测量 1s内执行 ~ 120次)调用。如果这个函数每秒调用20次也能满足页面效果的话,那这些额外的高频调用就是没有意义的。
类似的例子还有:搜索建议框。
降频两种策略
防抖(debounce): 连续高频调用函数,函数执行1次(看具体的实现细节)
节流(throttle): 连续高频调用函数,函数按指定频率(低频)执行多次
它们又细分立即执行版,非立即执行版,混合版
防抖代码
立即执行版
function debounce_callnow(f,t=3000){
var time = null
return function(){
if(!time){
f();
} else {
console.log("不要着急,等3s后再调用才有效")
}
clearTimeout(time)
time = setTimeout(()=>{
time = null;
},t)
}
const fn = () => { console.log(Date.now(),'鼠标移动了,我就执行')}
var f1 = debounce_callnow(fn)
document.addEventListener('mousemove',fn)
复制代码
非立即执行版
function debounce_callend(f,t=3000){
let time = null
return ()=>{
if(time) {
clearTimeout(time);
console.log('不是立即执行的,等3s后看结果');
}
time = setTimeout(()=>{
f();
},t)
}
}
复制代码
混合版本
function debounce_callboth(f,t=3000){
let time = null
return ()=>{
if(!time){
f();
}
clearTimeout(time)
time = setTimeout(()=>{
time = null;
f();
},t)
}
}
复制代码
开发中的应用
场景
- 节流:搜索建议框; onScroll事件处理
- 防抖:搜索建议框; 记录当前滚动条的位置
实施:
-
手写一个
-
采用第三方的库:
- 节流:underscore, a-hooks,vue-use
- 防抖:underscore, a-hooks,vue-use