节流和防抖
节流(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)
}
}
节流代码
参考:js函数-防抖与节流
开发中的应用
场景
- 节流:搜索建议框; onScroll事件处理
- 防抖:搜索建议框; 记录当前滚动条的位置
实施:
- 手写一个
- 采用第三方的库:
-
节流:underscore, a-hooks,vue-use
-
防抖:underscore, a-hooks,vue-use
-
拓展
搜索框按下1不放
淘宝:
jd:
天猫
人家根本不提供搜索建议
当当
苏宁
有一家上市公司的搜索框没有做任何的降频处理: www.smzdm.com/
参考:js函数-防抖与节流