Open yygmind opened 5 years ago
虽然看了很多防抖节流,但每次看都有不同的认识,写的很棒
我能问下一开始为啥要用闭包保存变量吗,好处在哪里
我能问下一开始为啥要用闭包保存变量吗,好处在哪里
这样就不用产生全局变量啊
if (remaining <= 0 || remaining > wait) remaining > wait 这个条件怎么成立的,没有想明白 推导 remaining > wait 的话 可以 得 now - previous < 0 这个是我怎么也想不通的成立条件
if (remaining <= 0 || remaining > wait) remaining > wait 这个条件怎么成立的,没有想明白 推导 remaining > wait 的话 可以 得 now - previous < 0 这个是我怎么也想不通的成立条件
防止更改系统时间的吧
@yygmind 思维导图看不到了
引言
上一节我们详细聊了聊高阶函数之柯里化,通过介绍其定义和三种柯里化应用,并在最后实现了一个通用的 currying 函数。这一小节会继续之前的篇幅聊聊函数节流 throttle,给出这种高阶函数的定义、实现原理以及在 underscore 中的实现,欢迎大家拍砖。
有什么想法或者意见都可以在评论区留言,下图是本文的思维导图,高清思维导图和更多文章请看我的 Github。
定义及解读
函数节流指的是某个函数在一定时间间隔内(例如 3 秒)只执行一次,在这 3 秒内 无视后来产生的函数调用请求,也不会延长时间间隔。3 秒间隔结束后第一次遇到新的函数调用会触发执行,然后在这新的 3 秒内依旧无视后来产生的函数调用请求,以此类推。
举一个小例子,不知道大家小时候有没有养过小金鱼啥的,养金鱼肯定少不了接水,刚开始接水时管道中水流很大,水到半满时开始拧紧水龙头,减少水流的速度变成 3 秒一滴,通过滴水给小金鱼增加氧气。
此时「管道中的水」就是我们频繁操作事件而不断涌入的回调任务,它需要接受「水龙头」安排;「水龙头」就是节流阀,控制水的流速,过滤无效的回调任务;「滴水」就是每隔一段时间执行一次函数,「3 秒」就是间隔时间,它是「水龙头」决定「滴水」的依据。
如果你还无法理解,看下面这张图就清晰多了,另外点击 这个页面 查看节流和防抖的可视化比较。其中 Regular 是不做任何处理的情况,throttle 是函数节流之后的结果,debounce 是函数防抖之后的结果(下一小节介绍)。
原理及实现
函数节流非常适用于函数被频繁调用的场景,例如:window.onresize() 事件、mousemove 事件、上传进度等情况。使用 throttle API 很简单,那应该如何实现 throttle 这个函数呢?
实现方案有以下两种
这里我们采用第一种方案来实现,通过闭包保存一个 previous 变量,每次触发 throttle 函数时判断当前时间和 previous 的时间差,如果这段时间差小于等待时间,那就忽略本次事件触发。如果大于等待时间就把 previous 设置为当前时间并执行函数 fn。
我们来一步步实现,首先实现用闭包保存 previous 变量。
执行 throttle 函数后会返回一个新的 function,我们命名为 betterFn。
betterFn 函数中可以获取到 previous 变量值也可以修改,在回调监听或事件触发时就会执行 betterFn,即
betterFn()
,所以在这个新函数内判断当前时间和 previous 的时间差即可。结合上面两段代码就实现了节流函数,所以完整的实现如下。
underscore 源码解读
上述代码实现了一个简单的节流函数,不过 underscore 实现了更高级的功能,即新增了两个功能
配置 { leading: false } 时,事件刚开始的那次回调不执行;配置 { trailing: false } 时,事件结束后的那次回调不执行,不过需要注意的是,这两者不能同时配置。
所以在 underscore 中的节流函数有 3 种调用方式,默认的(有头有尾),设置 { leading: false } 的,以及设置 { trailing: false } 的。上面说过实现 throttle 的方案有 2 种,一种是通过时间戳判断,另一种是通过定时器创建和销毁来控制。
第一种方案实现这 3 种调用方式存在一个问题,即事件停止触发时无法响应回调,所以 { trailing: true } 时无法生效。
第二种方案来实现也存在一个问题,因为定时器是延迟执行的,所以事件停止触发时必然会响应回调,所以 { trailing: false } 时无法生效。
underscore 采用的方案是两种方案搭配使用来实现这个功能。
小结
函数节流指的是某个函数在一定时间间隔内(例如 3 秒)只执行一次,在这 3 秒内 无视后来产生的函数调用请求
节流可以理解为养金鱼时拧紧水龙头放水,3 秒一滴
节流实现方案有 2 种
参考
文章穿梭机
❤️ 看完三件事
如果你觉得这篇内容对你挺有启发,我想邀请你帮我三个小忙: