性能一直是前端老生常谈的一个话题,其中有一个性能问题就是咱们会频繁的触发一些事件,例如mousemove、scroll、resize等,虽然浏览器已经对这些事件的触发作了一些优化,可是若是在很短的时间内频繁的触发仍然会影响性能,这个时候就须要今天的主角:防抖和节流,利用它们来进行优化,提升性能。前端
防抖就是将屡次高频操做优化为只在最后一次执行(某个函数在某段时间内,不管触发了多少次回调,都只执行最后一次)。一般的使用场景是:用户输入,只需在输入完成后作一次输入校验便可。浏览器
防抖是将屡次操做合并为一次操做完成,其原理就是维护一个计时器,在规定的时间后触发函数,可是在该规定时间内再次触发的话就会取消以前的定时器而从新设置,从而保证了只有最后一次操做可以被触发。其实现步骤以下所示:闭包
function debounce(fn, wait, immediate) { let timer = null; return function (...args) { // 当即执行的功能(timer为空表示首次触发) if (immediate && !timer) { fn.apply(this, args); } // 有新的触发,则把定时器清空 timer && clearTimeout(timer); // 从新计时 timer = setTimeout(() => { fn.apply(this, args); }, wait); } } 复制代码
观察效果图能够验证上述的理论知识:app
节流就是每隔一段时间后执行一次,也就是下降频率,将高频操做优化成低频操做。一般使用场景:滚动条事件、resize事件、动画等,一般每隔100-500ms执行一次便可。ide
节流函数的实现方式有两种:定时器版本、时间戳版本,这二者各有千秋,下面来简要实现一下。函数
21.2.2.1 定时器版本性能
定时器版本的节流函数其重点是利用闭包保存timer变量,具备两个特色:优化
// 定时器版本 function throttle(fn, wait) { let timer = null; return function(...args) { if (!timer) { timer = setTimeout(() => { fn.apply(this, args); timer = null; }, wait) } } } 复制代码
21.2.2.2 时间戳版本动画
时间戳版本的节流函数重点是利用闭包保存上一次的时间previous,具备两个特色:this
// 时间戳版本 function throttle(fn, wait) { // 上一次执行时间 let previous = 0; return function(...args) { // 当前时间 let now = +new Date(); if (now - previous > wait) { previous = now; fn.apply(this, args); } } } 复制代码
观察效果图能够验证上述的理论知识: