摘要:浅谈以及的原理和实现背景日常开发中我们经常会遇到一些需要节流调用或者压缩调用次数的情况例如之前我在完成一个需求的时候就遇到了因为后端并发问题导致收到多条信息从而导致函数被重复调用的情况当时的做法是通过对函数的调用进行注册遇到多次调用的时候清
浅谈throttle以及debounce的原理和实现 背景
日常开发中,我们经常会遇到一些需要节流调用,或者压缩调用次数的情况,例如之前我在完成一个需求的时候,就遇到了因为后端并发问题,导致收到多条socket信息从而导致函数被重复调用的情况,当时的做法是通过setTimeout对函数的调用进行注册,遇到多次调用的时候,清空前一次的调用,以后一次为准.后来在阅读underscore源码的时候,发现这种做法与debounce以及throttle的实现不谋而合.因而简单记录一下.
throttle与debouncethrottle与debounce在用于控制函数的多次调用的时候,非常的有效.throttle函数能够控制目标函数在一定的时间内最多只会调用一次.而debounce函数,则可以压缩调用的次数,把多次函数调用压缩成只调用一次(多次的函数调用之间的间隔不能超过规定的时间间隔).
这样文字描述起来可能比较难理解,不过不要紧,当初我在看underscore源码的时候,也是非常难以理解这两个函数的需求,感觉好像都差不多一样.而且underscore在1.1.3版本中,采用了相同的底层实现,只是接口传入的参数不同而已.因而我们这里采用一个坐电梯的例子来说明.
假设你正在准备乘坐电梯,并且电梯门准备关上然后上升的时候,你的同事来了,出于礼貌,我们需要停止电梯的关闭,让同事进入.假设源源不断的有同事进来的话,电梯就需要处于一种待机的状态,一直等待人员的进入,直到没有新的同事进入或者说电梯满了,这个时候,电梯才能运行.另外,同事的进入需要在电梯门的关闭之前,否则的话,就只能等下一趟了.
换成图示我们可以这么理解
上面一排方块为函数的调用,下面的方块则是函数实际的运行.我们可以看到,即使函数多次调用,在短暂的暂停后,函数只会运行一次.
debounce运用场景既然debounce函数可以把多次的函数调用压缩成一次,那么我们在进行Markdown渲染的时候,就可以排上用场了.如果我们在每一次键盘的敲击都进行一次Markdown渲染,必然会造成部分的计算冗余,同时也可能因为多次无畏的渲染导致页面卡顿,影响体验,因而我们可以使用debounce函数,把Markdown的渲染进行压缩,只在键盘敲击结束了一定的时间后((可以完成一次词语或者语句的输入),再进行渲染,能够减少许多冗余的计算,提高体验.
throttle电梯throttle电梯不想debounce电梯一样会无限的等待,而是我们设定一个时间,例如10s,那么10s内,其他的人可以不断的进入电梯,但是,一旦10s过去了,那么无论如何,电梯都会进入运行的状态.
换成图示,我们可以这么理解
上面一排的方块是函数的调用,我们可以看到,及时进行了多次的函数调用,函数也只会在隔一段时间实际运行一次,不会每一次的函数调用都运行
throttle也有另外一个称号,就是节流函数,顾名思义就是能够节省函数调用时的资源消耗,达到防止系统资源被一直大量占用,从而影响其他函数执行的情况.throttle一个运用的比较广泛的场景则是通过对scroll函数进行节流,因为每一次滚动页面,都有进行资源的消耗计算,但是完全没必要每一次滚动时间触发的时候,都进行计算,这样有可能会导致大量的计算堆积而出现跳帧的情况发生,因而我们需要使用throttle函数进行节流,在滚动事件发生了一段事件后,再统一的进行处理,只要时间设置的合理,用户一般是感知不到的.
debounce与throttle的原理与实现解释的再多,也不如我们直接自己实现一遍debounce与throttle,这样对于两个函数的运用和理解,都会更上一层楼.debounce与throttle在许多的库,例如jQuery,loadash以及underscore中都有实现,这里采用underscore的1.1.3版本的实现,非常简单而且能够达到目的(其实主要是最近在看underscore源码)
代码如下
// throttle 和 debouce 函数的底层实现 var limit = function(func, wait, debounce) { var timeout; return function() { var context = this, args = arguments; // 封装函数,用于延迟调用 var throttler = function() { // 只是节流函数的时候,对其timeout进行赋值为null,这样可以设置下一次的setTimtout timeout = null; func.apply(context, args); }; // 如果debouce是true的话,前一个函数的调用timeout会被清空,不会被执行 // 就是debounce函数的调用,这个前一个函数的不会执行.下面会重新设定setTimeout用于 // 执行这一次的调用. // 但是如果是throttle函数,则会执行前一个函数的调用,同时下面的setTimeout在 // 函数没有运行的时候,是无法再次设定的. if (debounce) clearTimeout(timeout); // 如果debouce是true 或者 timeout 为空的情况下,设置setTimeout if (debounce || !timeout) timeout = setTimeout(throttler, wait); }; }; // throttle 节流函数 _.throttle = function(func, wait) { return limit(func, wait, false); }; // debouce 多次调用,只执行最后一次. _.debounce = function(func, wait) { return limit(func, wait, true); };
代码上面都加了注释,比较好理解,而且也比较简单.通过代码,我们可以更加进一步的理解debounce与throttle的原理以及实现,主要都是通过标志位来判断是否要清空setTimeout以及是否要生成新的setTimeout
至此,debounce与throttle的原理以及实现基本就介绍完成了.写的不是特别的流畅,大家凑合着看,主要还是用于记录在日常工作中以及在源码阅读中遇到的一些小发现和小灵感.
参考jQuery throttle / debounce: Sometimes, less is more!
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/85195.html
摘要:如果想忽略结尾边界上的调用,传入返回客户调用函数上次执行时间点延迟执行函数若设定了开始边界不执行选项,上次执行时间始终为首次执行时,如果设定了开始边界不执行选项,将上次执行时间设定为当前时间。 Underscore.js 是一个很精干的库,压缩后只有5.2KB。它提供了几十种函数式编程的方法,弥补了标准库的不足,大大方便了JavaScript的编程。 本文仅探讨Unde...
摘要:如果想忽略结尾边界上的调用,传入返回客户调用函数上次执行时间点延迟执行函数若设定了开始边界不执行选项,上次执行时间始终为首次执行时,如果设定了开始边界不执行选项,将上次执行时间设定为当前时间。 文章转自:https://blog.coding.net/blog/...注: _.throttle 和 _.debounce是Underscore.js库的两个针对函数节流的方法,用于处理高频...
摘要:隆重请出主角防抖与节流。防抖与节流的异同相同都是防止某一时间段内,函数被频繁调用执行,通过时间频率控制,减少回调函数执行次数,来实现相关性能优化。参考文章分钟理解的节流防抖及使用场景函数防抖和节流 showImg(https://segmentfault.com/img/bVburM8?w=800&h=600); 本篇课题,或许早已是烂大街的解读文章。不过春招系列面试下来,不少伙伴们还...
摘要:函数分析标签空格分隔本文是源码剖析系列第六篇文章,上节我们介绍了节流函数的实现,这节将会介绍一下节流函数的兄弟防抖动函数。函数是在高频率触发的情况下,为了防止函数的频繁调用,将其限制在一段时间内只会调用一次。 underscore debounce函数分析 标签(空格分隔): underscore 本文是underscore源码剖析系列第六篇文章,上节我们介绍了throttle节流函...
阅读 3016·2021-11-11 16:55
阅读 3134·2021-10-18 13:34
阅读 576·2021-10-14 09:42
阅读 1623·2021-09-03 10:30
阅读 825·2021-08-05 10:02
阅读 938·2019-08-30 11:27
阅读 3466·2019-08-29 15:14
阅读 1218·2019-08-29 13:02