在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实现随机返回数组的一个元素
Aug 13 Javascript
JS在IE和FF下attachEvent,addEventListener学习笔记
Nov 26 Javascript
js 点击按钮弹出另一页,选择值后,返回到当前页
May 26 Javascript
JQuery做的一个简单的点灯游戏分享
Jul 16 Javascript
jQuery结合HTML5制作的爱心树表白动画
Feb 01 Javascript
深入浅析JavaScript中的scrollTop
Jul 11 Javascript
JavaScript自定义函数实现查找两个字符串最长公共子串的方法
Nov 24 Javascript
浅谈Angular路由守卫
Aug 26 Javascript
vue.js+element-ui动态配置菜单的实例
Sep 07 Javascript
简述pm2常用命令集合及配置文件说明
May 30 Javascript
浅谈webpack和webpack-cli模块源码分析
Jan 19 Javascript
vue 内联样式style中的background用法说明
Aug 05 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
PHP 文件缓存的性能测试
2010/04/25 PHP
PHP基础陷阱题(变量赋值)
2012/09/12 PHP
php数据类型判断函数有哪些
2013/09/23 PHP
php while循环得到循环次数
2013/10/26 PHP
PHP使用mysql_fetch_object从查询结果中获取对象集的方法
2015/03/18 PHP
php过滤htmlspecialchars() 函数实现把预定义的字符转换为 HTML 实体用法分析
2019/06/25 PHP
laravel 创建命令行命令的图文教程
2019/10/23 PHP
javascript 表单规则集合对象
2009/07/21 Javascript
Javascript解决常见浏览器兼容问题的12种方法
2010/01/04 Javascript
javascript椭圆旋转相册实现代码
2012/01/16 Javascript
(跨浏览器基础事件/浏览器检测/判断浏览器)经验代码分享
2013/01/24 Javascript
JQuery异步获取返回值中文乱码的解决方法
2015/01/29 Javascript
jquery实现相册一下滑动两次的方法
2015/02/09 Javascript
浅谈js的html元素的父节点,子节点
2016/08/06 Javascript
Chrome浏览器的alert弹窗禁止再次弹出后恢复的方法
2016/12/30 Javascript
Vue.js实现多条件筛选、搜索、排序及分页的表格功能
2020/11/24 Javascript
Node.js实现mysql连接池使用事务自动回收连接的方法示例
2018/02/03 Javascript
JavaScript中常见内置函数用法示例
2018/05/14 Javascript
vuejs 制作背景淡入淡出切换动画的实例
2018/09/01 Javascript
axios携带cookie配置详解(axios+koa)
2018/12/28 Javascript
JS中使用react-tooltip插件实现鼠标悬浮显示框
2019/05/15 Javascript
微信小程序实现蒙版弹出窗功能
2019/09/17 Javascript
[04:09]2018年度DOTA2社区贡献奖-完美盛典
2018/12/16 DOTA
Python中用sleep()方法操作时间的教程
2015/05/22 Python
python安装cx_Oracle模块常见问题与解决方法
2017/02/21 Python
pyqt5的QComboBox 使用模板的具体方法
2018/09/06 Python
pandas pivot_table() 按日期分多列数据的方法
2018/11/16 Python
Python基于pandas绘制散点图矩阵代码实例
2020/06/04 Python
Pytorch如何切换 cpu和gpu的使用详解
2021/03/01 Python
Flesh Beauty官网:露华浓集团旗下彩妆品牌
2021/02/15 全球购物
银行稽核岗位职责
2015/04/13 职场文书
2015年学校财务工作总结
2015/05/19 职场文书
2015法院个人工作总结范文
2015/05/25 职场文书
Python函数中apply、map、applymap的区别
2021/11/27 Python
Windows Server 2019 域控制器安装图文教程
2022/04/28 Servers
使用CSS实现黑白格背景效果
2022/06/01 HTML / CSS