VueUse 是如何封装函数节流的?

函数节流

基本概念

函数节流是高频率执行函数的一种优化方式,另一种方式是函数防抖,函数节流和函数防抖的区别是:

  • 函数节流是在一定时间内只执行一次函数。
  • 函数防抖是在函数被触发一定时间后再执行,如果在这时间段内又被触发,则重新计时。

实现

throttleFn 实现了函数节流,返回的新函数执行时就会有节流效果。

throttleFn 函数有两个参数:要执行的函数 fn 和时间段 delay, 返回的新函数会设置一个定时器,在 delay 时间之后才会执行 fn 并清空 timeout

如果在定时器到期之前这个新函数再次被调用,fn 不会执行,这里定时器没有销毁,加上会更加严谨些。

优化

定时器

定时器仅仅只是计划代码在未来的某个时间执行(但是并不保证在该时间点一定执行)。执行时机是不能保证的,因为定时器只是在指定时间后将执行的函数放入执行队列中等待执行,只有当进程空闲时才会从执行队列中取出执行。

如图,添加了 200ms 的定时器,在 600ms 时会将要执行的函数放入执行队列中,这时主进程是空闲状态,就会从执行队列中取出要执行的函数执行。

如果在 250ms 时添加了 100ms 的定时器,那么 350ms 时将要执行的函数放入执行队列中,但此时主进程还在执行JavaScript代码,定时器代码最终是在 400ms 主进程空闲后才执行。

时间戳来实现函数节流

相对定时器有以下优势:

  • 实时性:定时器的执行时间可能会延后执行,时间戳能更精确的控制函数的执行。
  • 性能消耗:频繁的创建定时器有一定的性能消耗,时间戳的方式不用管理定时器。
  • 执行方式:定时器是异步执行的,时间戳是同步执行的。

缺点:

  • 执行函数如果是很耗时的操作,时间戳的同步执行反而会阻塞进程而使得页面卡顿。
  • 时间戳的方式在最后一次执行的函数可能会被忽略,导致没有记录到最后一次的状态。比如在图片懒加载中用的话,就会出现问题。

图片懒加载的实现是 onscroll 事件中判断图片是否在可视区域内,onscroll 事件可以采用函数节流来进行优化,如果不记录最后一次 onscroll 事件的触发执行,就不能准确的判断图片最后是否在可视区域内。

useThrottleFn

VueUse 中使用 useThrottleFn 来实现函数节流。

使用

基本实现

首先 useThrottleFn 是采用时间戳的方式来实现函数节流。

上面提到时间戳的方式有两个问题:

第一个问题是执行函数如果是很耗时的操作的话,时间戳的同步执行返回会阻塞进程而使得页面卡顿,这个问题可以将函数的执行转为异步来解决。

第二个问题是最后一次执行的函数可能会被忽略,导致没有记录到最后一次的状态,解决这个问题可以采用定时器来设置最后一次执行。

函数加了 trailing 参数,为 true 时会执行间隔小于 delay 的加一个定时器作为最后一次执行。

异步处理

现在异步操作一般都是用 Promise 更好一些,因此对定时器做一层 Promise 封装方便获取返回值。

封装完之后,返回的新函数的返回值可能是 Promise 或者其他值,这里统一返回 Promise 更方便使用者处理。

功能拆分

我们可以将 throttleFn 函数里面的功能拆分封装。

节流的部分进行封装:

Promise 部分进行封装:

配置项扩展

添加this绑定

类似 Function.prototype.call 一样将 this 绑定的对象作为第一个参数:

使用:

首次不执行

有些场景下是希望节流的函数第一次不执行,比如在 loading 延迟赋值场景下。

loading 延迟赋值:

一般我们在发送请求获取数据的时会显示一个 loading 的效果,目的告知用户当前正在加载数据,请等待。以提升用户体验,但如果获取数据的时间很快的话,loading 的效果一闪而过反而体验不好。因此对loading 进行延迟赋值,也就是抽出一小段时间用来网络请求,超出这段时间再显示 loading,没有超出就不显示 loading,如果这一小段时间够短,那么用户是几乎感知不到的。

第一次 throttledFn(true) 不马上执行,而是等超过 500ms 才执行,这里就需要函数节流首次调用不马上执行。useThrottleFn 通过 leading 配置首次不执行。

ms 可能 Ref 对象或函数

完整代码:

rejectOnCancel 配置

rejectOnCancel 用于取消定时器后触发 Promisereject 方法。

细节优化

throttleFn 改名为 useThrottleFn,并调整参数顺序方便使用。

相关推荐
customer083 分钟前
【开源免费】基于SpringBoot+Vue.JS周边产品销售网站(JAVA毕业设计)
java·vue.js·spring boot·后端·spring cloud·java-ee·开源
清灵xmf4 分钟前
TypeScript 类型进阶指南
javascript·typescript·泛型·t·infer
小白学大数据10 分钟前
JavaScript重定向对网络爬虫的影响及处理
开发语言·javascript·数据库·爬虫
qq_3901617719 分钟前
防抖函数--应用场景及示例
前端·javascript
334554321 小时前
element动态表头合并表格
开发语言·javascript·ecmascript
John.liu_Test1 小时前
js下载excel示例demo
前端·javascript·excel
Yaml41 小时前
智能化健身房管理:Spring Boot与Vue的创新解决方案
前端·spring boot·后端·mysql·vue·健身房管理
PleaSure乐事1 小时前
【React.js】AntDesignPro左侧菜单栏栏目名称不显示的解决方案
前端·javascript·react.js·前端框架·webstorm·antdesignpro
哟哟耶耶1 小时前
js-将JavaScript对象或值转换为JSON字符串 JSON.stringify(this.SelectDataListCourse)
前端·javascript·json
getaxiosluo1 小时前
react jsx基本语法,脚手架,父子传参,refs等详解
前端·vue.js·react.js·前端框架·hook·jsx