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 相关文章推荐
静态图片的十一种滤镜效果--不支持Ie7及非IE浏览器。
Mar 06 Javascript
自写简单JS判断是否已经弹出页面
Oct 20 Javascript
Prototype源码浅析 String部分(四)之补充
Jan 16 Javascript
关于使用 jBox 对话框的提交不能弹出问题解决方法
Nov 07 Javascript
jQuery中的height innerHeight outerHeight区别示例介绍
Jun 15 Javascript
jQuery使用之标记元素属性用法实例
Jan 19 Javascript
JavaScript中点击事件的写法
Jun 28 Javascript
jQuery插件zTree实现删除树子节点的方法示例
Mar 08 Javascript
Bootstrap模态框插入视频的实现代码
Jun 25 Javascript
js实现登录时记住密码的方法分析
Apr 05 Javascript
javascript自定义加载loading效果
Sep 15 Javascript
JavaScript 判断浏览器是否是IE
Feb 19 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
一个程序下载的管理程序(一)
2006/10/09 PHP
Windows IIS PHP 5.2 安装与配置方法
2009/06/08 PHP
php at(@)符号的用法简介
2009/07/11 PHP
Joomla下利用configuration.php存储简单数据
2010/05/19 PHP
php设计模式 Factory(工厂模式)
2011/06/26 PHP
探讨:如何使用PhpDocumentor生成文档
2013/06/25 PHP
去除php注释和去除空格函数分享
2014/03/13 PHP
PHP经典面试题集锦
2015/03/19 PHP
WordPress主题制作中自定义头部的相关PHP函数解析
2016/01/08 PHP
基于jquery封装的一个js分页
2011/11/15 Javascript
详解JavaScript编程中正则表达式的使用
2015/10/25 Javascript
js的各种排序算法实现(总结)
2016/07/23 Javascript
利用jquery实现下拉框的禁用与启用
2016/12/07 Javascript
使用ES6语法重构React代码详解
2017/05/09 Javascript
vue中路由验证和相应拦截的使用详解
2017/12/13 Javascript
利用Node.js批量抓取高清妹子图片实例教程
2018/08/02 Javascript
解决vue接口数据赋值给data没有反应的问题
2018/08/27 Javascript
详解React项目中碰到的IE问题
2019/03/14 Javascript
vue v-for循环重复数据无法添加问题解决方法【加track-by='索引'】
2019/03/15 Javascript
Vue 实现CLI 3.0 + momentjs + lodash打包时优化
2019/11/13 Javascript
vue中对象数组去重的实现
2020/02/06 Javascript
[03:42]2014DOTA2西雅图国际邀请赛7月9日TOPPLAY
2014/07/09 DOTA
python计算一个序列的平均值的方法
2015/07/11 Python
详解Python Socket网络编程
2016/01/05 Python
Python类的动态修改的实例方法
2017/03/24 Python
Python 解决中文写入Excel时抛异常的问题
2018/05/03 Python
OpenCV图像颜色反转算法详解
2019/05/13 Python
python 日期排序的实例代码
2019/07/11 Python
Python 正则表达式爬虫使用案例解析
2019/09/23 Python
Scrapy爬虫文件批量运行的实现
2020/09/30 Python
Python调用ffmpeg开源视频处理库,批量处理视频
2020/11/16 Python
毕业生找工作推荐信
2013/11/21 职场文书
优秀学生评语大全
2014/04/25 职场文书
党员剖析材料范文
2014/12/18 职场文书
《语言的突破》读后感3篇
2019/12/12 职场文书
Django实现在线无水印抖音视频下载(附源码及地址)
2021/05/06 Python