本文转载自微信公众号《三分钟学会前端》,作者安姐。转载本文请联系三分钟学习前端公众号。上次手写一个节流函数throttle,这周继续手写一个debounce函数debounce。debounce是指某个函数在一定时间内,无论触发多少次回调,最后一次只执行一次。实现原理是使用定时器,在函数第一次执行的时候设置一个定时器,调用时发现已经设置了定时器,然后清除之前的定时器,重新设置一个新的定时器。清除的定时器在定时器超时时触发函数的执行。//fn是需要防抖处理的函数//wait是时间间隔functiondebounce(fn,wait=50){//通过闭包缓存一个定时器idlettimer=null//将去抖处理结果作为函数返回//Trigger回调事件时执行这个返回函数。returnfunction(...args){//this保存到contextconstcontext=this//如果已经设置了定时器,清除上一个定时器if(timer)clearTimeout(timer)//开始设置一个新的定时器,执行传入的函数定时器结束后fntimer=setTimeout(()=>{fn.apply(context,args)},wait)}}//DEMO//执行debounce函数并返回新的FunctionconstbetterFn=debounce(()=>console.log('fn防抖执行'),1000)//停止滑动1秒后执行函数()=>console.log('fn防抖执行')document.addEventListener('scroll',betterFn)然而,debounceinunderscore有第三个参数:immediate。这个参数有什么用?将immediate设为true,debounce将在等待间隔开始时调用此函数。(注意:并且在wait的时间内,不会再调用。)在不小心点了两次提交按钮,提交了两次的情况下很有用。给immediate参数传true会让debounce在wait时间开始计算前触发函数(即无延迟触发函数),而不是wait时间后触发函数,wait期间不会触发time(相当于锁定fn的执行)。如果不小心点击了两次提交按钮,第二次提交将不会被执行。然后我们根据immediate的值来决定如何执行fn。在immediate的情况下,我们立即执行fn,并在等待时间内锁定fn的执行。等待时间触发后,会重新执行fn,以此类推。//immediate表示是否执行functiondebounce(fn,wait=50,immediate){lettimer=nullreturnfunction(...args){//this保存到contextconstcontext=thisif(timer)clearTimeout(timer)//immediate为true表示在第一次触发后执行//timer为空表示第一次触发)}}//DEMO//执行debounce函数并返回一个新函数constbetterFn=debounce(()=>console.log('fn防抖被执行'),1000,true)//第一次滚动被触发执行一次fn,函数fndocument.addEventListener('scroll',betterFn)underscore源码分析停止滑动1秒后才执行对于函数,学习优秀思想,直接上传代码和评论。本源码分析依赖underscore1.9.1版本的实现。//这里的三个参数上面解释了_.debounce=function(func,wait,immediate){//timeout表示timer//result表示func执行返回值vartimeout,result;//timer结束后//1,清空定时器,这样就不会影响下一次连续事件的触发//2、触发并执行funcvarlater=function(context,args){timeout=null;//if(args)判断是过滤并立即触发//的association在于_.delay和restArgumentsif(args)result=func.apply(context,args);};//将debounce处理的结果作为函数返回vardebounced=restArguments(function(args){if(timeout)clearTimeout(timeout);if(immediate){//第一次触发后会设置超时时间,//可以根据超时时间是否为空来判断是否是第一次触发varcallNow=!timeout;timeout=setTimeout(later,wait);if(callNow)result=func.apply(this,args);}else{//设置定时器timeout=_.delay(later,wait,this,args);}returnresult;});//添加手动取消去抖动.cancel=function(){clearTimeout(timeout);timeout=null;};returndebounced;};//延迟执行函数func_.delay=restArguments(function(func,wait,args){returnsetTimeout(function(){returnfunc.申请(空,参数);},等待);});与上面的基本实现相比,underscore有以下功能。1、函数func执行后,返回结果值result2。定时器计时结束后,清除超时,这样就不会影响下一次连续事件的触发。3.新增手动取消功能cancel4。immediate为true后,第一次触发时只执行第一个Execute,频繁触发回调后不会执行
