摘要:基础防抖我们现在写一个最基础的防抖处理标记事件也做如下改写现在试一下,我们会发现只有我们停止滚动秒钟的时候,控制台才会打印出一行随机数。
为何要防抖和节流
有时候会在项目开发中频繁地触发一些事件,如 resize、 scroll、 keyup、 keydown等,或者诸如输入框的实时搜索功能,我们知道如果事件处理函数无限制调用,会大大加重浏览器的工作量,有可能导致页面卡顿影响体验;后台接口的频繁调用,不仅会影响客户端体验,还会大大增加服务器的负担。而如果对这些调用函数增加一个限制,让其减少调用频率,岂不美哉?
针对这个问题,一般有两个方案:
防抖 (Debounce)
节流 (Throttle)
我对函数防抖的定义:当函数被连续调用时,该函数并不执行,只有当其全部停止调用超过一定时间后才执行1次。
一个被经常提起的例子:
上电梯的时候,大家陆陆续续进来,电梯的门不会关上,只有当一段时间都没有人上来,电梯才会关门。
Talk is cheap,我们直接 show code 吧。
先做基本的准备(篇幅原因,HTML部分省略):
let container = document.getElementById("container"); // 事件处理函数 function handle(e) { onsole.log(Math.random()); } // 添加滚动事件 container.addEventListener("scroll", handle);
我们发现,每滚动一下,控制台就会打印出一行随机数。
基础防抖我们现在写一个最基础的防抖处理:
function debounce(func, wait) { var timeout;//标记 return function() { clearTimeout(timeout); timeout = setTimeout(func, wait); } }
事件也做如下改写:
container.addEventListener("scroll", debounce(handle, 1000));
现在试一下, 我们会发现只有我们停止滚动1秒钟的时候,控制台才会打印出一行随机数。
标准防抖以上基础版本会有两个问题,请看如下代码:
// 处理函数 function handle(e) { console.log(this); //输出Window对象 console.log(e); //undefined }
没错,当我们不使用防抖处理时,handle()函数的this指向调用此函数的container,而在外层使用防抖处理后,this的指向会变成Window。
其次,我们也要获取到事件对象event。
所以我们要对防抖函数做以下改写:
function debounce(fn, wait) { let timeout; return function() { clearTimeout(timeout); timeout = setTimeout(()=>{ fn.apply(this,arguments)//使用apply改变this指向 }, wait); } }
当然了,如果使用箭头函数便可以省去外层声明。
先触发式防抖以上的情况都是只有当连续触发停止后才执行,那如果我们想让事件第一次触发就执行,后面的连续触发都不执行,直到停止触发一段时间才可以再次触发(比如防止频繁点击),该如何处理呢?
那么可以利用同样的原理,稍作修改即可:
function debounce(fn, wait) { let timeout; return function(){ let arg = arguments; let that = this; clearTimeout(timeout); !timeout && fn.apply(that,arg) timeout = setTimeout(function(){ timeout = null; }, wait); } }节流 (Throttle)
顾名思义,节流就是节约流量,将连续触发的事件稀释成预设评率。
比如每间隔1秒执行一次函数,无论这期间触发多少次事件。
这有点像公交车, 无论在站点等车的人多不多,公交车只会按时来一班,不会来一个人就来一辆公交车。
标准节流function throttle(fn, wait) { let timeout; return function () { if (!timeout) { timeout = setTimeout(() => { timeout = null; fn.apply(this, arguments) }, wait) } } }
用滚动事件来描述节流,其实是一个非常典型的场景,比如需要用滚动事件判断是否加载更多等。
先触发式节流和防抖函数类似,以上的情况是先等待后触发,如果我们想让事件先触发后等待,该如何处理呢?网上大部分文章都告诉你用时间戳的方式去实现,其实只要像防抖一样稍作修改即可实现。
function throttle(fn, wait) { let timeout; return function () { if (!timeout) { fn.apply(this, arguments) timeout = setTimeout(() => { timeout = null; }, wait) } } }
这样,我们就会发现第一次触发函数就会立即生效。
总结关于防抖与节流,lodash、underscore等工具库都有完善的实现可以直接用,本没有必要造轮子。本文的目的仅仅是为了将其主要思想和实现思路展现出来。更重要的,知道防抖和节流的本质后,就知道在何时使用防抖或者节流,何时先触发或后触发。无论需求如何改变,都可以灵活的运用。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/104789.html
摘要:函数防抖和节流,都是控制事件触发频率的方法。封装一个函数,让持续触发的事件监听是我们封装的这个函数,将目标函数作为回调传进去,等待一段时间过后执行目标函数第二点实现了,再看第一点持续触发不执行。 曾经面试时候被问到过这个,年少的我一脸无知。。。 后来工作中遇到了一个场景:输入名称的同时去服务器校验名称是否重复,但发现之前的代码竟然都没做限制,输入一次发一次请求。简直忍不了,就在项目的u...
摘要:关于防抖与节流的应用和解释自行查找资料。修改如果有定时器就清除如果时间满足就让他不满足总之除了第一次就只让其中一个执行一开始执行一次时间戳,最后停止在执行一次。 这一篇文章我想写一下防抖与节流,因为我自己不是很理解而且说实话,以前知道,但是老忘,虽然概念还有一些简单的写法会,但还是缺乏练习和深刻的理解。 showImg(https://segmentfault.com/img/remo...
摘要:若时间差大于间隔时间,则立刻执行一次函数。不同点函数防抖,在一段连续操作结束后,处理回调,利用和实现。函数防抖关注一定时间连续触发的事件只在最后执行一次,而函数节流侧重于一段时间内只执行一次。 原博客地址,欢迎star 函数防抖和节流 函数防抖和函数节流:优化高频率执行js代码的一种手段,js中的一些事件如浏览器的resize、scroll,鼠标的mousemove、mouseover...
摘要:对象是无法通过这种方式深拷贝。这就是函数防抖和节流要做的事情。函数防抖当触发频率过高时函数基本停止执行而函数节流则是按照一定的频率执行事件。 对象的深浅拷贝 对象的深拷贝与浅拷贝的区别: 浅拷贝:仅仅复制对象的引用, 而不是对象本身。 深拷贝:把复制的对象所引用的全部对象都复制一遍 浅拷贝的实现: var obj = { age : 18, person : { ...
摘要:文章来源详谈防抖和节流轻松理解函数节流和函数防抖函数防抖和节流好啦,今天的小菊花课堂之的防抖与节流的内容就告一段落啦,感各位能耐心看到这里。 前言 陆游有一首《冬夜读书示子聿》——古人学问无遗力,少壮工夫老始成。纸上得来终觉浅,绝知此事要躬行。,其中的意思想必大家都能明白,在学习或工作中,不断的印证着这首诗的内涵。所以,又有了此篇小菊花文章。 详解 在前端开发中,我们经常会碰到一些会持...
阅读 2388·2021-09-22 16:01
阅读 3156·2021-09-22 15:41
阅读 1173·2021-08-30 09:48
阅读 492·2019-08-30 15:52
阅读 3328·2019-08-30 13:57
阅读 1715·2019-08-30 13:55
阅读 3653·2019-08-30 11:25
阅读 758·2019-08-29 17:25