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 相关文章推荐
jQuery(1.3.2) 7行代码搞定跟随屏幕滚动的层
May 21 Javascript
javascript中的prototype属性实例分析说明
Aug 09 Javascript
JavaScript Accessor实现说明
Dec 06 Javascript
Textarea与懒惰渲染实现代码
Jan 04 Javascript
在JavaScript中typeof的用途介绍
Apr 11 Javascript
jquery常用方法及使用示例汇总
Nov 08 Javascript
jQuery实现的网页右下角tab样式在线客服效果代码
Oct 23 Javascript
bootstrap table动态加载数据示例代码
Mar 25 Javascript
VueJs 将接口用webpack代理到本地的方法
Nov 27 Javascript
element-ui table span-method(行合并)的实现代码
Dec 20 Javascript
ES6中的Javascript解构的实现
Oct 30 Javascript
Vue中nprogress页面加载进度条的方法实现
Nov 13 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
jquery+php+ajax显示上传进度的多图片上传并生成缩略图代码
2014/10/15 PHP
js+php实现静态页面实时调用用户登陆状态的方法
2015/01/04 PHP
php采集中国代理服务器网的方法
2015/06/16 PHP
php版微信小店API二次开发及使用示例
2016/11/12 PHP
javascript radio 联动效果
2009/03/04 Javascript
Javascript 中介者模式实例
2009/12/16 Javascript
document.write的几点使用心得
2014/05/14 Javascript
jquery取消事件冒泡的三种方法(推荐)
2016/05/28 Javascript
Bootstrap编写一个兼容主流浏览器的受众巨幕式风格页面
2016/07/01 Javascript
工作中比较实用的JavaScript验证和数据处理的干货(经典)
2016/08/03 Javascript
nodejs基础知识
2017/02/03 NodeJs
利用ES6语法重构React组件详解
2017/03/02 Javascript
JS简单实现获取元素的封装操作示例
2017/04/07 Javascript
JavaScript数据结构之广义表的定义与表示方法详解
2017/04/12 Javascript
vuejs实现递归树型菜单组件
2018/01/13 Javascript
Node.js成为Web应用开发最佳选择的原因
2018/02/05 Javascript
JavaScript如何对图片进行黑白化
2018/04/10 Javascript
Vue作用域插槽slot-scope实例代码
2018/09/05 Javascript
Bootstrap实现前端登录页面带验证码功能完整示例
2020/03/26 Javascript
vue $mount 和 el的区别说明
2020/09/11 Javascript
js实现贪吃蛇游戏(简易版)
2020/09/29 Javascript
vue2.0 watch里面的 deep和immediate用法说明
2020/10/30 Javascript
JS中箭头函数与this的写法和理解
2021/01/14 Javascript
[06:07]辉夜杯现场观众互动 “比谁远送显示器”
2015/12/26 DOTA
一篇文章搞定Python操作文件与目录
2019/08/13 Python
python 并发编程 多路复用IO模型详解
2019/08/20 Python
python爬虫开发之Beautiful Soup模块从安装到详细使用方法与实例
2020/03/09 Python
python爬虫判断招聘信息是否存在的实例代码
2020/11/20 Python
Python+unittest+requests+excel实现接口自动化测试框架
2020/12/23 Python
施华洛世奇澳大利亚官网:SWAROVSKI澳大利亚
2017/01/06 全球购物
P D PAOLA法国官网:西班牙著名的珠宝首饰品牌
2020/02/15 全球购物
教师现实表现材料
2014/02/14 职场文书
矿泉水广告词
2014/03/20 职场文书
市级绿色学校申报材料
2014/08/25 职场文书
小学安全工作总结2015
2015/05/18 职场文书
tensorflow中的梯度求解及梯度裁剪操作
2021/05/26 Python