摘要:函数分析标签空格分隔本文是源码剖析系列第六篇文章,上节我们介绍了节流函数的实现,这节将会介绍一下节流函数的兄弟防抖动函数。函数是在高频率触发的情况下,为了防止函数的频繁调用,将其限制在一段时间内只会调用一次。
underscore debounce函数分析
标签(空格分隔): underscore
本文是underscore源码剖析系列第六篇文章,上节我们介绍了throttle节流函数的实现,这节将会介绍一下节流函数的兄弟 —— debounce防抖动函数。
throttle函数是在高频率触发的情况下,为了防止函数的频繁调用,将其限制在一段时间内只会调用一次。而debounce函数则是在频繁触发的情况下,只在触发的最后一次调用一次,想像一下如果我们用手按住一个弹簧,那么只有等到我们把手松开,弹簧才会弹起来,下面我用一个电梯的例子来介绍debounce函数。
假如我下班的时候去坐电梯,等了一段时间后,电梯正准备关上门下降,这个时候一个同事走了过来,电梯门被打开,这样电梯就会继续等一段时间,如果中间一直有人进来,那么电梯就一直不会下降,直到最后一个人进来后过了一定时间后还没有下一个人进来,这时电梯才会下降。
应用场景除了电梯,事实上我们还有很多应用场景,比如我用键盘不断输入文字,我希望等最后一次输入结束后才会调用接口来请求展示联想词,如果每次输入一个字的时候就会调用接口,这样调用未免太过于频繁了。
没有debounce时:
有debounce时:
知道debounce的工作原理了,我们可以先自己实现一个比较简单的debounce函数。
function debounce(func, wait) { var timeout, args, context var later = function() { func.apply(context, args) timeout = context = args = null } return function() { context = this args = arguments // 每次触发都清理掉前一次的定时器 clearTimeout(timeout) // 只有最后一次触发后才会调用later timeout = setTimeout(later, wait) } }
麻雀虽小,五脏俱全,不过这个函数还是有很多问题,比如每次触发都设置了太多的setTimeout,这样会比较耗费cpu,我们来看一下underscore的实现方式。
underscore debounce// debounce函数传入三个参数,分别是要执行的函数func,延迟时间wait,是否立即执行immediate // 如果immediate为true,那么就会在wait时间段一开始就执行一次func,之后不管触发多少次都不会再执行func // 在类似不小心点了提交按钮两下而提交了两次的情况下很有用 _.debounce = function (func, wait, immediate) { var timeout, args, context, timestamp, result; var later = function () { // 这个是最关键的一步,因为每次触发的时候都要记录当前timestamp // 但是later是第一次触发后wait时间后执行的,_now()减去第一次触发时的时间当然是等于wait的 // 但是如果后续继续触发,那么_.now() - timestamp肯定会小于wait // last是执行later的时间和上一次触发的时间差 var last = _.now() - timestamp; // 如果在later执行前还有其他触发,那么就会重新设置定时器 // last >= 0应该是防止客户端系统时间被调整 if (last < wait && last >= 0) { timeout = setTimeout(later, wait - last); // 如果last大于等于wait,也就是说设置timeout定时器后没有再触发过 } else { timeout = null; // 这个时候如果immediate不为true,就会立即执行func函数,这也是为什么immediate为true的时候只会执行第一次触发 if (!immediate) { result = func.apply(context, args); // 解除引用 if (!timeout) context = args = null; } } }; return function () { context = this; args = arguments; // 每次触发都用timestamp记录时间戳 timestamp = _.now(); // 第一次进来的时候,如果immediate为true,那么会立即执行func var callNow = immediate && !timeout; // 第一次进来的时候会设置一个定时器 if (!timeout) timeout = setTimeout(later, wait); if (callNow) { result = func.apply(context, args); context = args = null; } return result; }; };
为了防止出现我们上面那种不停地设置定时器的情况,underscore只在later函数中在上一次定时器执行结束后才重新设置定时器。
如果传入的immediate为true,那么只会在第一次进来的时候立即执行。很明显在上面代码中func执行只有两处,一个是callNow判断里面,一个是!immediate判断里面,所以这样保证了后续触发不会再执行func。
参考链接:
1、浅谈throttle以及debounce的原理和实现
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/52065.html
摘要:函数分析标签空格分隔本文是源码剖析系列第六篇文章,上节我们介绍了节流函数的实现,这节将会介绍一下节流函数的兄弟防抖动函数。函数是在高频率触发的情况下,为了防止函数的频繁调用,将其限制在一段时间内只会调用一次。 underscore debounce函数分析 标签(空格分隔): underscore 本文是underscore源码剖析系列第六篇文章,上节我们介绍了throttle节流函...
摘要:直接来分析返回的匿名函数部分。我第一次调用事件函数是在,按照设定,之后才能调用第二次方法,在这秒内,任何调用都是不执行的。这个难点解决了,其他就都好说。恩,那这个的解读就结束了,有什么地方我没写清楚的话,请给我留言。 刚写完一篇debounce(防抖)函数的实现,我又看了下underscore.js的实现方法。算是趁热打铁,分析一下underscore里实现的套路。 先贴上源码: _....
摘要:事情是如何发生的最近干了件事情,发现了源码的一个。楼主找到的关于和区别的资料如下关于拿来主义为什么这么多文章里会出现泽卡斯的错误代码楼主想到了一个词,叫做拿来主义。的文章,就深刻抨击了拿来主义这一现象。 事情是如何发生的 最近干了件事情,发现了 underscore 源码的一个 bug。这件事本身并没有什么可说的,但是过程值得我们深思,记录如下,各位看官仁者见仁智者见智。 平时有浏览别...
摘要:专题系列预计写二十篇左右,主要研究日常开发中一些功能点的实现,比如防抖节流去重类型判断拷贝最值扁平柯里递归乱序排序等,特点是研究和的实现方式。如果有错误或者不严谨的地方,请务必给予指正,十分感谢。 JavaScript 专题系列第一篇,讲解防抖,带你从零实现一个 underscore 的 debounce 函数 前言 在前端开发中会遇到一些频繁的事件触发,比如: window 的 r...
阅读 728·2021-11-24 10:19
阅读 1106·2021-09-13 10:23
阅读 3428·2021-09-06 15:15
阅读 1776·2019-08-30 14:09
阅读 1681·2019-08-30 11:15
阅读 1837·2019-08-29 18:44
阅读 932·2019-08-29 16:34
阅读 2455·2019-08-29 12:46