在VUE中使用lodash的debounce和throttle操作


Posted in Javascript onNovember 09, 2020

说明:

debounce和throttle在脚手架的使用,此处以防抖函数debounce为例避免按钮被重复点击

引入:

import lodash from 'lodash'

使用:

直接使用debounce方法

// 审核
   audit: lodash.debounce(function() {
     this.$refs['model'].saveTotalResult(1).then(() => {
      const reportId = this.activeReport.id;
      report.audit(reportId).then(res => {
   successMsg(res.msg)
      })
     })
    }, 300)

补充知识:在 Vue 中使用lodash对事件进行防抖和节流

有些浏览器事件可以在短时间内快速触发多次,比如调整窗口大小或向下滚动页面。

例如,监听页面窗口滚动事件,并且用户持续快速地向下滚动页面,那么滚动事件可能在 3 秒内触发数千次,这可能会导致一些严重的性能问题。

如果在面试中讨论构建应用程序,出现滚动、窗口大小调整或按下键等事件请务必提及 防抖(Debouncing) 和 函数节流(Throttling)来提升页面速度和性能。这两兄弟的本质都是以闭包的形式存在。通过对事件对应的回调函数进行包裹、以自由变量的形式缓存时间信息,最后用 setTimeout 来控制事件的触发频率。

Throttle:第一个人说了算

throttle 的中心思想在于:在某段时间内,不管你触发了多少次回调,我都只认第一次,并在计时结束时给予响应。

先给大家讲个小故事:现在有一个旅客刚下了飞机,需要用车,于是打电话叫了该机场唯一的一辆机场大巴来接。司机开到机场,心想来都来了,多接几个人一起走吧,这样这趟才跑得值——我等个十分钟看看。于是司机一边打开了计时器,一边招呼后面的客人陆陆续续上车。在这十分钟内,后面下飞机的乘客都只能乘这一辆大巴,十分钟过去后,不管后面还有多少没挤上车的乘客,这班车都必须发走。

在这个故事里,“司机” 就是我们的节流阀,他控制发车的时机;“乘客”就是因为我们频繁操作事件而不断涌入的回调任务,它需要接受“司机”的安排;而“计时器”,就是我们上文提到的以自由变量形式存在的时间信息,它是“司机”决定发车的依据;最后“发车”这个动作,就对应到回调函数的执行。

总结下来,所谓的“节流”,是通过在一段时间内无视后来产生的回调请求来实现的。只要一位客人叫了车,司机就会为他开启计时器,一定的时间内,后面需要乘车的客人都得排队上这一辆车,谁也无法叫到更多的车。

对应到实际的交互上是一样一样的:每当用户触发了一次 scroll 事件,我们就为这个触发操作开启计时器。一段时间内,后续所有的 scroll 事件都会被当作“一辆车的乘客”——它们无法触发新的 scroll 回调。直到“一段时间”到了,第一次触发的 scroll 事件对应的回调才会执行,而“一段时间内”触发的后续的 scroll 回调都会被节流阀无视掉。

现在一起实现一个 throttle:

// fn是我们需要包装的事件回调, interval是时间间隔的阈值
function throttle(fn, interval) {
 // last为上一次触发回调的时间
 let last = 0
 
 // 将throttle处理结果当作函数返回
 return function () {
   // 保留调用时的this上下文
   let context = this
   // 保留调用时传入的参数
   let args = arguments
   // 记录本次触发回调的时间
   let now = +new Date()
 
   // 判断上次触发的时间和本次触发的时间差是否小于时间间隔的阈值
   if (now - last >= interval) {
   // 如果时间间隔大于我们设定的时间间隔阈值,则执行回调
     last = now;
     fn.apply(context, args);
   }
  }
}
 
// 用throttle来包装scroll的回调
const better_scroll = throttle(() => console.log('触发了滚动事件'), 1000)

Debounce:最后一个人说了算

防抖的中心思想在于:我会等你到底。在某段时间内,不管你触发了多少次回调,我都只认最后一次。

继续讲司机开车的故事。这次的司机比较有耐心。第一个乘客上车后,司机开始计时(比如说十分钟)。十分钟之内,如果又上来了一个乘客,司机会把计时器清零,重新开始等另一个十分钟(延迟了等待)。直到有这么一位乘客,从他上车开始,后续十分钟都没有新乘客上车,司机会认为确实没有人需要搭这趟车了,才会把车开走。

我们对比 throttle 来理解 debounce:在throttle的逻辑里,“第一个人说了算”,它只为第一个乘客计时,时间到了就执行回调。而 debounce 认为,“最后一个人说了算”,debounce 会为每一个新乘客设定新的定时器。

现在一起实现一个 debounce:

// fn是我们需要包装的事件回调, delay是每次推迟执行的等待时间
function debounce(fn, delay) {
 // 定时器
 let timer = null
 
 // 将debounce处理结果当作函数返回
 return function () {
  // 保留调用时的this上下文
  let context = this
  // 保留调用时传入的参数
  let args = arguments
 
  // 每次事件被触发时,都去清除之前的旧定时器
  if(timer) {
    clearTimeout(timer)
  }
  // 设立新定时器
  timer = setTimeout(function () {
   fn.apply(context, args)
  }, delay)
 }
}
 
// 用debounce来包装scroll的回调
const better_scroll = debounce(() => console.log('触发了滚动事件'), 1000)

用 Throttle 来优化 Debounce

debounce 的问题在于它“太有耐心了”。试想,如果用户的操作十分频繁——他每次都不等 debounce 设置的 delay 时间结束就进行下一次操作,于是每次 debounce 都为该用户重新生成定时器,回调函数被延迟了不计其数次。频繁的延迟会导致用户迟迟得不到响应,用户同样会产生“这个页面卡死了”的观感。

为了避免弄巧成拙,我们需要借力 throttle 的思想,打造一个“有底线”的 debounce——等你可以,但我有我的原则:delay 时间内,我可以为你重新生成定时器;但只要delay的时间到了,我必须要给用户一个响应。这个 throttle 与 debounce “合体”思路,已经被很多成熟的前端库应用到了它们的加强版 throttle 函数的实现中:

// fn是我们需要包装的事件回调, delay是时间间隔的阈值
function throttle(fn, delay) {
 // last为上一次触发回调的时间, timer是定时器
 let last = 0, timer = null
 // 将throttle处理结果当作函数返回
 
 return function () { 
  // 保留调用时的this上下文
  let context = this
  // 保留调用时传入的参数
  let args = arguments
  // 记录本次触发回调的时间
  let now = +new Date()
 
  // 判断上次触发的时间和本次触发的时间差是否小于时间间隔的阈值
  if (now - last < delay) {
  // 如果时间间隔小于我们设定的时间间隔阈值,则为本次触发操作设立一个新的定时器
    clearTimeout(timer)
    timer = setTimeout(function () {
     last = now
     fn.apply(context, args)
    }, delay)
  } else {
    // 如果时间间隔超出了我们设定的时间间隔阈值,那就不等了,无论如何要反馈给用户一次响应
    last = now
    fn.apply(context, args)
  }
 }
}
 
// 用新的throttle包装scroll的回调
const better_scroll = throttle(() => console.log('触发了滚动事件'), 1000) 
document.addEventListener('scroll', better_scroll)

在 Vue 里使用 lodash 中的 Debouncing 和 Throttling

事件节流和防抖是提高性能或降低网络开销的好方法。虽然 Vue 1曾经支持对事件的节流和防抖,但是在Vue 2中为了保持核心的简单性,删除对事件的节流和防抖的支持。因此,在Vue 2对对事件进行防抖和节流我们可以使用 lodash 来做。

安装

可以通过 yarn 或 npm 安装 lodash。

# Yarn

$ yarn add lodash

# NPM

$ npm install lodash --save

注意:如果我们不想导入lodash的所有内容,而只导入所需的部分,则可以通过一些Webpack构建自定义来解决问题。还可以使用lodash.throttle和lodash.debounce等软件包分别安装和导入lodash的各个部分。

throttling 方法

要对事件进行节流处理方法非常简单,只需将要调用的函数包装在lodash的_.throttle函数中即可。

<template>
 <button @click="throttledMethod()">Click me as fast as you can!</button>
</template>
 
<script>
import _ from 'lodash'
 
export default {
 methods: {
  throttledMethod: _.throttle(() => {
   console.log('I get fired every two seconds!')
  }, 2000)
 }
}
</script>

debouncing 方法

尽管节流在某些情况下很有用,但一般情况我们经常使用的是防抖。防抖实质上将我们的事件分组在一起,并防止它们被频繁触发。要在Vue组件中使用节流,只需将要调用的函数包装在lodash的_.debounce函数中。

<template>
 <button @click="throttledMethod()">Click me as fast as you can!</button>
</template>
 
<script>
import _ from 'lodash'
 
export default {
 methods: {
  throttledMethod: _.debounce(() => {
   console.log('I only get fired once every two seconds, max!')
  }, 2000)
 }
}
</script>

以上这篇在VUE中使用lodash的debounce和throttle操作就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
js 新浪的一个图片播放图片轮换效果代码
Jul 15 Javascript
基于jQuery的合并表格中相同文本的相邻单元格的代码
Apr 06 Javascript
jQuery内容过滤选择器用法分析
Feb 10 Javascript
下雪了 javascript实现雪花飞舞
Aug 02 Javascript
jQuery+CSS实现一个侧滑导航菜单代码
May 09 Javascript
详谈表单格式化插件jquery.serializeJSON
Jun 23 jQuery
Angular实现的自定义模糊查询、排序及三角箭头标注功能示例
Dec 28 Javascript
vue 虚拟dom的patch源码分析
Mar 01 Javascript
vue自定义底部导航栏Tabbar的实现代码
Sep 03 Javascript
vue使用keep-alive实现组件切换时保存原组件数据方法
Oct 30 Javascript
js实现扫雷源代码
Nov 27 Javascript
使用Canvas绘制一个游戏人物属性图
Mar 25 Javascript
解决vue init webpack 下载依赖卡住不动的问题
Nov 09 #Javascript
详解nginx配置vue h5 history去除#号
Nov 09 #Javascript
axios解决高并发的方法:axios.all()与axios.spread()的操作
Nov 09 #Javascript
vue 解决在微信内置浏览器中调用支付宝支付的情况
Nov 09 #Javascript
详解Vue中的watch和computed
Nov 09 #Javascript
vue-axios同时请求多个接口 等所有接口全部加载完成再处理操作
Nov 09 #Javascript
解决vue 使用axios.all()方法发起多个请求控制台报错的问题
Nov 09 #Javascript
You might like
jQuery Mobile + PHP实现文件上传
2014/12/12 PHP
php读取flash文件高宽帧数背景颜色的方法
2015/01/06 PHP
由php中字符offset特征造成的绕过漏洞详解
2017/07/07 PHP
Yii框架使用PHPExcel导出Excel文件的方法分析【改进版】
2019/07/24 PHP
Thinkphp5.0 框架的请求方式与响应方式分析
2019/10/14 PHP
flash javascript之间的通讯方法小结
2008/12/20 Javascript
js中巧用cssText属性批量操作样式
2011/03/13 Javascript
jQuery拖动元素并对元素进行重新排序
2015/12/30 Javascript
javascript history对象详解
2017/02/09 Javascript
简单实现jQuery上传图片显示预览功能
2020/06/29 jQuery
node.js操作MongoDB的实例详解
2017/10/11 Javascript
vue组件之Alert的实现代码
2017/10/17 Javascript
Angular2中监听数据更新的方法
2018/08/31 Javascript
基于vue-cli 路由 实现类似tab切换效果(vue 2.0)
2019/05/08 Javascript
koa中间件核心(koa-compose)源码解读分析
2020/06/15 Javascript
Python下使用Psyco模块优化运行速度
2015/04/05 Python
python实现汉诺塔方法汇总
2016/07/25 Python
Python图算法实例分析
2016/08/13 Python
Python利用递归和walk()遍历目录文件的方法示例
2017/07/14 Python
分享vim python缩进等一些配置
2018/07/02 Python
浅谈python实现Google翻译PDF,解决换行的问题
2018/11/28 Python
python日志logging模块使用方法分析
2019/05/23 Python
Python识别快递条形码及Tesseract-OCR使用详解
2019/07/15 Python
在Pycharm中调试Django项目程序的操作方法
2019/07/17 Python
python中wx模块的具体使用方法
2020/05/15 Python
python获取系统内存占用信息的实例方法
2020/07/17 Python
前端使用canvas生成盲水印的加密解密的实现
2020/12/16 HTML / CSS
韩国演唱会订票网站:StubHub韩国
2019/01/17 全球购物
英国在线药房和在线药剂师:Chemist 4 U
2020/01/05 全球购物
外贸业务员求职信范文
2013/12/12 职场文书
工作疏忽检讨书
2014/01/25 职场文书
《最大的“书”》教学反思
2014/02/14 职场文书
成绩单公证书
2014/04/10 职场文书
学习十八大宣传标语
2014/10/09 职场文书
芙蓉镇观后感
2015/06/10 职场文书
十八大观后感
2015/06/12 职场文书