JS函数节流和防抖之间的区分和实现详解


Posted in Javascript onJanuary 11, 2019

在写JS时,这两个函数比较常见,有时候傻傻分不清用哪个,或者说知道代码要怎么写,但要说出它究竟是节流函数还是防抖函数时一脸楞逼。今天有一个同学分享了这两个的区分,我也来回顾一下,加深一下印象,以便日后用到时心里有底。PS:百度和谷歌搜索前几个介绍都是相反介绍,本文为原创,如有雷同纯属抄袭我的。

节流概念(Throttle)

按照设定的时间固定执行一次函数,比如200ms一次。注意:固定就是你在mousemove过程中,执行这个节流函数,它一定是200ms(你设定的定时器延迟时间)内执行一次。没到200ms,一定会返回,没有执行回调函数的。

主要应用场景有:scroll、touchmove

防抖概念(Debounce)

抖动停止后的时间超过设定的时间时执行一次函数。注意:这里的抖动停止表示你停止了触发这个函数,从这个时间点开始计算,当间隔时间等于你设定时间,才会执行里面的回调函数。如果你一直在触发这个函数并且两次触发间隔小于设定时间,则一定不会到回调函数那一步。

主要应用场景有:input验证、搜索联想、resize

节流实现

思路: 第一次先设定一个变量true,第二次执行这个函数时,会判断变量是否true,是则返回。当第一次的定时器执行完函数最后会设定变量为flase。那么下次判断变量时则为flase,函数会依次运行。

代码一:首次不执行

function throttle(fn,delay=100){
 //首先设定一个变量,在没有执行我们的定时器时为null
 let timer = null;
 return function(){
 //当我们发现这个定时器存在时,则表示定时器已经在运行中,需要返回
 if(timer) return;
 timer = setTimeout(()=>{
 fn.apply(this,arguments);
 timer = null;
 },delay);
 }
}

代码二:首次执行

function throttle2(fn,delay=100){
 let last = 0;
 return function(){
 let curr = +new Date();
 if(curr - last > delay){
 fn.apply(this,arguments);
 last = curr;
 }
 }
}

防抖实现

思路:首次运行时把定时器赋值给一个变量,第二次执行时,如果间隔没超过定时器设定的时间则会清除掉定时器,重新设定定时器,依次反复,当我们停止下来时,没有执行清除定时器,超过一定时间后触发回调函数。

代码一:首次不执行

function debounce(fn,delay=200){
 let timer = null;
 return function(){
 if(timer) clearTimeout(timer);
 timer = setTimeout(()=>{
 fn.apply(this,arguments);
 timer = null;
 },delay);
 }
}

代码二:首次执行

function debounce2(fn, delay = 200, atBegin = true) {
 let timer = null, last = 0,during;
 return function () {
 let self = this, args = arguments;
 var exec = function () {
 fn.apply(self, args);
 }
 if (atBegin && !timer) {
 exec();
 atBegin = false;
 } else {
 during = Date.now() - last;
 if (during > delay) {
 exec();
 } else {
 if (timer) clearTimeout(timer);
 timer = setTimeout(function () {
  exec();
 }, delay);
 }
 }
 last = Date.now();
 }
}

上面的代码只是我自己的一个简单实现,看看lodash里面的两个核心实现代码。生产中建议使用它们的库,毕竟有这么多人在用,出bug的机会比较少,我上面的代码有可能有一些情况没考虑到。如果你发现有问题的,也请告诉我。

如果在项目中有需要用到的,可以直接安装单个的NPM模块。throttle 和 debounce

lodash使用使用文档

lodash库里面这两个函数设置的参数有点复杂,记录一下里面的参数和代码使用。

节流(throttle)

官方文档解释:

创建一个节流函数,在 wait 秒内最多执行 func 一次的函数。 该函数提供一个 cancel 方法取消延迟的函数调用以及 flush 方法立即调用。 可以提供一个 options 对象决定如何调用 func 方法, options.leading 与|或 options.trailing 决定 wait 前后如何触发。 func 会传入最后一次传入的参数给这个函数。 随后调用的函数返回是最后一次 func 调用的结果。

注意: 如果 leading 和 trailing 都设定为 true 则 func 允许 trailing 方式调用的条件为: 在 wait 期间多次调用。

如果 wait 为 0 并且 leading 为 false, func调用将被推迟到下一个点,类似setTimeout为0的超时。

参数

func (Function)
要节流的函数

[wait=0] (number)
需要节流的毫秒

[options] (Object)
选项对象

[options.leading=true] (boolean)
指定调用在节流开始前

[options.trailing=true] (boolean)
指定调用在节流结束后

返回值 (Function)

返回节流的函数

示例

// 避免在滚动时过分的更新定位
jQuery(window).on('scroll', _.throttle(updatePosition, 100));

// 点击后就调用 `renewToken`,但5分钟内超过1次。
var throttled = _.throttle(renewToken, 300000, { 'trailing': false });
jQuery(element).on('click', throttled);

// 取消一个 trailing 的节流调用
jQuery(window).on('popstate', throttled.cancel);

防抖(debounce)

创建一个 debounced(防抖动)函数,该函数会从上一次被调用后,延迟 wait 毫秒后调用 func 方法。 debounced(防抖动)函数提供一个 cancel 方法取消延迟的函数调用以及 flush 方法立即调用。 可以提供一个 options(选项) 对象决定如何调用 func 方法,options.leading 与 options.trailing 决定延迟前后如何触发(先调用后等待 还是 先等待后调用)。 func 调用时会传入最后一次提供给 debounced(防抖动)函数 的参数。 后续调用的 debounced(防抖动)函数返回是最后一次 func 调用的结果。

注意: 如果 leading 和 trailing 选项为 true, 则 func 允许 trailing 方式调用的条件为: 在 wait 期间多次调用防抖方法。

如果 wait 为 0 并且 leading 为 false, func调用将被推迟到下一个点,类似setTimeout为0的超时。

参数

func (Function)
要防抖动的函数

[wait=0] (number)
需要延迟的毫秒数

[options] (Object)
选项对象

[options.leading=false] (boolean)
指定调用在延迟开始前

[options.maxWait] (number)
设置 func 允许被延迟的最大值

[options.trailing=true] (boolean)
指定调用在延迟结束后

返回值 (Function)

返回具有防抖动功能的函数

示例

// 避免窗口在变动时出现昂贵的计算开销。
jQuery(window).on('resize', _.debounce(calculateLayout, 150));

// 当点击时 `sendMail` 随后就被调用。
jQuery(element).on('click', _.debounce(sendMail, 300, {
 'leading': true,
 'trailing': false
}));

// 确保 `batchLog` 调用1次之后,1秒内会被触发。
var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
var source = new EventSource('/stream');
jQuery(source).on('message', debounced);

// 取消一个 trailing 的防抖动调用
jQuery(window).on('popstate', debounced.cancel);

以上就是这篇节流和防抖的全部介绍,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
解决FLASH需要点击激活的代码
Dec 20 Javascript
符合标准的js表单提交的代码
Sep 13 Javascript
基于Jquery的简单图片切换效果
Jan 06 Javascript
js String对象中常用方法小结(字符串操作)
Jan 27 Javascript
表格单元格交错着色实现思路及代码
Apr 01 Javascript
Jquery实现控件的隐藏和显示实例
Feb 08 Javascript
JavaScript和JQuery的鼠标mouse事件冒泡处理
Jun 19 Javascript
jQuery提示插件qTip2用法分析(支持ajax及多种样式)
Jun 08 Javascript
node实现简单的反向代理服务器
Jul 26 Javascript
vue之a-table中实现清空选中的数据
Nov 07 Javascript
ES6中Set和Map用法实例详解
Mar 02 Javascript
JavaScript仿京东秒杀倒计时
Mar 17 Javascript
微信公众号H5支付接口调用方法
Jan 10 #Javascript
详解在Node.js中发起HTTP请求的5种方法
Jan 10 #Javascript
vue实现压缩图片预览并上传功能(promise封装)
Jan 10 #Javascript
微信小程序地图(map)组件点击(tap)获取经纬度的方法
Jan 10 #Javascript
最简单的JS实现json转csv的方法
Jan 10 #Javascript
puppeteer实现html截图的示例代码
Jan 10 #Javascript
其实你可以少写点if else与switch(推荐)
Jan 10 #Javascript
You might like
php实现点击可刷新验证码
2015/11/07 PHP
Ubuntu VPS中wordpress网站打开时提示”建立数据库连接错误”的解决办法
2016/11/03 PHP
Laravel6.18.19如何优雅的切换发件账户
2020/06/14 PHP
脚本之家贴图转换+转贴工具用到的js代码超级推荐
2007/04/05 Javascript
Jquery操作Select 简单方便 一个js插件搞定
2009/11/12 Javascript
关于Jqzoom的使用心得 jquery放大镜效果插件
2010/04/12 Javascript
基于jQuery的360图片展示实现代码
2012/06/14 Javascript
html的DOM中document对象forms集合用法实例
2015/01/21 Javascript
Javascript显示和隐藏ul列表的方法
2015/07/15 Javascript
理解javascript封装
2016/02/23 Javascript
JS无缝滚动效果实现方法分析
2016/12/21 Javascript
JavaScript中在光标处插入添加文本标签节点的详细方法
2017/03/22 Javascript
react中使用swiper的具体方法
2018/05/15 Javascript
微信小程序扫描二维码获取信息实例详解
2019/05/07 Javascript
python三元运算符实现方法
2013/12/17 Python
使用Python中的cookielib模拟登录网站
2015/04/09 Python
python PyTorch参数初始化和Finetune
2018/02/11 Python
基于MTCNN/TensorFlow实现人脸检测
2018/05/24 Python
python 请求服务器的实现代码(http请求和https请求)
2018/05/25 Python
使用python对多个txt文件中的数据进行筛选的方法
2019/07/10 Python
Kali Linux安装ipython2 和 ipython3的方法
2019/07/11 Python
python3图片文件批量重命名处理
2019/10/31 Python
Python实现bilibili时间长度查询的示例代码
2020/01/14 Python
美国健康和保健平台:healtop
2020/07/02 全球购物
师范教师毕业鉴定
2014/01/13 职场文书
求职意向书
2014/07/29 职场文书
课外访万家心得体会
2014/09/03 职场文书
解除劳动合同协议书(样本)
2014/10/02 职场文书
计生办班子群众路线教育实践活动个人对照检查材料思想汇报
2014/10/04 职场文书
2015年银行个人工作总结
2015/05/14 职场文书
2015年青年教师工作总结
2015/05/25 职场文书
大学开学典礼新闻稿
2015/07/17 职场文书
值班管理制度范本
2015/08/06 职场文书
解决sql server 数据库,sa用户被锁定的问题
2021/06/11 SQL Server
解决springboot druid数据库连接失败后一直重连的方法
2022/04/19 Java/Android
不想升级Win11?教你彻底锁定老版Windows系统的方法(附下载地址)
2022/09/23 数码科技