Js中的防抖与节流
为什么需要防抖和节流? 日常与浏览器打交道比较多的前端开发者对于浏览器的各种事件想必都不会陌生,我们会针对某一个特定的事件绑定对应的响应函数,在事件被触发时让浏览器自动调用该函数。 1 2 3 4 5 function onResizeHandler() { // do something on resize } window.addEventListener('resize', onResizeHandler); 如果只是一些触发频率很低的事件,那么上面的代码并没有什么问题。但是如果像resize这样可能在短时间内被频繁触发的事件(比如click/keydown/touchStart等),我们不去做任何的处理的话,可能导致事件的响应函数在短时间内被大量的触发,造成浏览器卡顿,伤害用户体验。 而节流和防抖一个很经典的应用场景就是去控制我们的事件的触发,节省浏览器开销。 什么是防抖 JavaScript中的防抖指的是只有在x ms内没有调用该函数,才会真正调用该函数。如下图 该图上方是事件触发的次数,下方是响应函数触发的次数,可以发现在事件大量被触发时(色块密集),响应函数并没有被触发。当事件停止触发一段事件后(三个色块的时间间隔)后,响应函数才会被真正的触发。 如果你想自己试试上面的例子,可以访问这个 codePen 。 防抖的简单实现 防抖函数其实是一个高阶函数,接收一个函数和防抖事件作为参数,返回值为防抖处理的函数。 的实现其实很简单,我们需要的是是一个定时器,如果在定时器的定时结束前,响应函数被触发的话则重置这个定时器的时间。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 function debounce(fn, wait, leading=false) { /** @type {number} */ let timer; /** @type {number} */ let lastCallTime; /** @type {boolean} */ let isInvoked = false; return function debounced(...args) { const context = this; const thisCallTime = Date.now(); if(leading) { if(!isInvoked) { fn.apply(context, args); isInvoked = true; } if(thisCallTime - lastCallTime >= wait) { fn.apply(context, args); } lastCallTime = Date.now(); return; } clearTimeout(timer); timer = setTimeout(() => fn.apply(context, args), wait); } } 需要注意的是,上面的函数添加了leading参数。传统的防抖函数响应函数第一次触发也需要等待x ms,使用该参数可让响应函数立即进行触发。 ...