前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >函数节流与函数防抖

函数节流与函数防抖

作者头像
贾顺名
发布2019-12-05 19:17:53
4570
发布2019-12-05 19:17:53
举报
文章被收录于专栏:全沾开发(huā)全沾开发(huā)

函数节流与函数防抖

函数节流和函数防抖是一个老生常谈的话题了,两者都是对大量频繁重复调用代码的一种优化方案 今天在某群和大家讨论时,顺便搜了一些相关博客 发现有一篇关于两者的定义竟然写反了。。。所以决定自己来写一下-.-权当加深记忆了

函数节流(throttle)

正如其命名的含义,节流。 限制函数在一定时间内调用的次数。

类似的实际生活中的场景

早晚高峰的地铁排队。

早高峰的地铁站
早高峰的地铁站

太多的人拥挤到站台上,大家都想搭上这班车,人挤人之间,难免会出现一些问题。 所以在很多地铁站,高峰期会设置很多层的屏障,来增加你进站的时间,从而减少站台的压力。

节流的实践
节流的实践

在程序中的实践

同理,代入程序中,我们可以通过限制函数调用的频率,来抑制资源的消耗。 比如我们要实现一个元素拖拽的效果,我们是可以在每次move事件中都进行重绘DOM,但是这样做,程序的开销是非常大的。 所以在这里我们可以用到函数节流的方法,来减少重绘的次数:

代码语言:javascript
复制
// 普通方案
$dragable.addEventListener('mousemove', () => {
  console.log('trigger')
})

// 函数节流的实现方案
let throttleIdentify = 0
$dragable.addEventListener('mousemove', () => {
  if (throttleIdentify) return
  throttleIdentify = setTimeout(() => throttleIdentify = 0, 500)
  console.log('trigger')
})

这样来做的话,在拖动的过程中,能保证500ms内,只会重绘一次DOM。 在同时监听了mouseover后,两者最终的效果是一致的,但是在拖动的过程中,函数节流版触发事件的次数会减少很多,遂消耗更少的资源。

通用的函数节流实现

代码语言:javascript
复制
/**
 * 函数节流的实现
 * @param  {Function} func      要实现函数节流的原函数
 * @param  {Number}   interval  节流的间隔
 * @return {Function}           添加节流功能的函数
 */
function throttle (func, interval) {
  let identify = 0
  return (...args) => {
    if (identify) return
    identify = setTimeout(() => identify = 0, interval)
    func.apply(this, args)
  }
}

类似函数节流的操作

平时开发中经常会做的ajax请求获取数据,这里可以用到类似函数节流的操作。 在我们发送一个请求到后台时,当返回的数据还没有接收到时,我们会添加一个标识,来表明当前有一个请求正在被处理,如果这时用户再触发ajax请求,则会直接跳过本次函数的执行。 同样的还有滑动加载更多数据,如果不添加类似的限制,可能会导致发送多条请求,渲染重复数据。

我曾经在某软件里遇到过-.-连续点击登录按钮数十次,结果连着给我弹了三次密码错误,随后告诉我输入密码错误超过三次,您的账号已被锁定。

函数节流的定义:限制函数在一定时间内调用的次数

函数防抖(debounce)

是函数在特定的时间内不被再调用后执行。

实际的例子

还是拿城市交通工具来说事儿。。 坐公交时,到站了,是由司机来操作车门的开合的。 当司机准备离站时,关闭车门,这是突然跑过来一人,司机只好再将车门打开,让人上来。

又或者,乘坐升降电梯时,电梯门关闭后,外边跑来一人又将电梯门按开。 这两件事儿都是因为关门这一个事件处理太快导致的,徒增一次开关门的消耗。

在程序中的实践

监听窗口大小重绘的操作。

在用户拖拽窗口时,一直在改变窗口的大小,如果我们在resize事件中进行一些操作,消耗将是巨大的。 而且大多数可能是无意义的执行,因为用户还处于拖拽的过程中。 所以我们可以用函数防抖来优化相关的处理

代码语言:javascript
复制
// 普通方案
window.addEventListener('resize', () => {
  console.log('trigger')
})

// 函数防抖方案
let debounceIdentify = 0
window.addEventListener('resize', () => {
  debounceIdentify && clearTimeout(debounceIdentify)
  debounceIdentify = setTimeout(() => {
    console.log('trigger')
  }, 300)
})

我们在resize事件中添加了一个300ms的延迟执行逻辑。 并且在每次事件触发时,都会重新计时,这样做也就可以保证,函数的执行肯定是在距离上次resize事件被触发的300ms后。 两次resize事件间隔小于300ms的都会被忽略,这样就节省了很多无意义的事件触发。

输入框的输入联想

几乎所有的搜索引擎都会对你输入的文字进行预判,并在下方推荐相关的结果。 但是这个联想意味着我们需要将当前用户所输入的文本传递到后端,并获取返回数据,展示在页面中。 如果遇到打字速度快的人,比如260字母/分钟的我,在一小段时间内,会连续发送大量的ajax请求到后端。 并且当前边的数据返回过来后,其实已经失去了展示的意义,因为用户可能从you输入到了young,这两个单词相关的结果肯定是不一样的。 所以我们就可以在监听用户输入的事件那里做函数防抖的处理,在XXX秒后发送联想搜索的ajax请求。

通用的函数防抖实现

代码语言:javascript
复制
/**
 * 函数防抖的实现
 * @param  {Function} func   要实现函数节流的原函数
 * @param  {Number}   delay  结束的延迟时间
 * @return {Function}        添加节流功能的函数
 */
function debounce (func, delay) {
  let debounceIdentify = 0
  return (...args) => {
    debounceIdentify && clearTimeout(debounceIdentify)
    debounceIdentify = setTimeout(() => {
      debounceIdentify = 0
      func.apply(this, args)
    }, delay)
  }
}

类似函数防抖的操作

在一些与用户的交互上,比如提交表单后,一般都会显示一个loading框来提示用户,他提交的表单正在处理中。 但是发送表单请求后就显示loading是一件很不友好的事情,因为请求可能在几十毫秒内就会得到响应。 这样在用户看来就是页面中闪过一团黑色,所以可以在提交表单后添加一个延迟函数,在XXX秒后再显示loading框。 这样在快速响应的场景下,用户是不会看到一闪而过的loading框,当然,一定要记得在接收到数据后去clearTimeout

代码语言:javascript
复制
let identify = setTimeout(showLoadingModal, 500)
fetch('XXX').then(res => {
  // doing something

  // clear timer
  clearTimeout(identify)
})

函数防抖的定义:函数在特定的时间内不被再调用后执行

总结

函数节流、函数防抖 两者都是用来解决代码短时间内大量重复调用的方案。 当然,也是各有利弊。 在实际开发中,两者的界定也很模糊。 比如搜索关键字联想,用节流或者防抖都可以来做,拖拽DOM、监听resize等等,这两个都是可以来实现的。

两者的区别在于: 函数节流在一定时间内肯定会触发多次,但是最后不一定会触发 函数防抖可能仅在最后触发一次

记住上边这两句,我觉得遇到类似需要进行优化的场景,应该就能够知道该用哪个了。

参考资料

  1. Javascript debounce vs throttle function
  2. Javascript function debounce and throttle
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 函数节流与函数防抖
    • 函数节流(throttle)
      • 类似的实际生活中的场景
      • 在程序中的实践
      • 通用的函数节流实现
      • 类似函数节流的操作
    • 函数防抖(debounce)
      • 实际的例子
      • 在程序中的实践
      • 通用的函数防抖实现
      • 类似函数防抖的操作
    • 总结
      • 参考资料
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档