防抖(debounce)和节流(throttle)
场景说明:一般我们在前端页面中会给元素绑定click、scroll、onmousemove、resize等事件,这些事件的执行函数如果是去发请求获取数据的话,我们无意识的连续点击或者连续滚动会给服务器带来很大的压力,因此我们需要在连续触发事件的时候设定每隔一段时间再去执行事件函数,这就是防抖和节流出现的背景。
例如:
<div id="content" style="height:150px;background-color:#ccc;"></div>
let content = document.getElementById('content'); function fetchData(){ console.log('我是测试数据'); } content.onmousemove = fetchData();
以上代码为div元素绑定了onmousemove事件,当鼠标经过div在其上移动时,会连续触发事件,假设事件执行函数需要去请求数据,则会一直发起请求,造成不必要的服务器压力。
1、防抖
概念:指出发时间后在n秒内只能执行一次,若在n秒内又触发了事件,则会重新计算函数执行时间
防抖函数分为立即执行版和非立即执行版
(1)立即执行版
立即执行即触发事件后函数立即执行,然后在n秒内不能触发事件才能继续执行函数的效果,假设在n秒内一直触发事件则函数永远不会执行直到停止触发n秒之后,实现如下:
function debounce(func,wait){ let timer; return function(){ let context = this; let args = arguments; if(timer) clearTimeout(timer); let callNow = !timer; //记录计时器是否结束 timer = setTimeout(()=>{ time = null; },wait); if(callNow){ func.apply(context,args); } } }
context.onmouseover = debounce(fetchData,1000);
(2)非立即执行版
非立即执行即触发事件之后函数不会立即执行,而是在n秒之后执行,如果在n秒内又触发了事件,则会重新计算函数的执行时间。实现如下:
function debounce(func,wait){ let timer; return function(){ let contex = this; let args = arguments; if(timer) clearTimeout(timer); timer = setTimeout(()=>{ func.apply(contex,arguments); },wait) } } context.onmousemove = debounce(fetchData,1000)
2、节流
概念:指连续触发的事件在n秒内只能执行一次
节流也有两种实现方式,一种是利用时间戳,一种是利用定时器。
(1)时间戳
function throttle(func,wait){ let last = 0;//上次触发时间戳 return function(){ let contex = this; let args = arguments; let now = +new Date(); //当前时间戳 if(now - last>wait){ //时间间隔大于wait时执行 last = now; func.apply(context,args); } } }
(2)定时器
function throttle(func,wait){ let timer; return function(){ let context = this; let args = arguments; if(!timer){ timer = setTimeout(()=>{ timer = null; func.apply(context,args) },wait) } } }