前言

首先来举个例子。百度首页的百度输入框,用户输入的时候,每次输入的信息,我们都能看到百度服务器返回给我们的联想关键字。我们每改动一个字,它就换一次联想词,这是我们肉眼能看到的速度,实际上如果不加以处理,可能已经上服务器发起了好几十次的同一个关键字联想请求了,具体速度依赖于不同的pc等机器上的运行速度不同。那么,刚刚也谈到,对于同一个关键字,请求这么多次,也许想给用户呈现的就一次,剩下的请求都是浪费的,并且如果成千上万甚至上亿的用户同时请求,对服务器的负担是巨大的。

防抖与节流解决的问题

从上面的例子,我们需要寻求一个解决方案。防抖和节流就是针对响应跟不上触发频率这类问题的两种解决方案。在给DOM绑定事件时,有些事件我们是无法控制触发频率的。 如鼠标移动事件onmousemove, 滚动滚动条事件onscroll,窗口大小改变事件onresize,瞬间的操作都会导致这些事件会被高频触发。 如果事件的回调函数较为复杂,就会导致响应跟不上触发,出现页面卡顿,假死现象。 在实时检查输入时,如果我们绑定onkeyup事件发请求去服务端检查,用户输入过程中,事件的触发频率也会很高,会导致大量的请求发出,响应速度会大大跟不上触发。

debounce和throttling的策略

针对此类快速连续触发和不可控的高频触发问题,debounce 和 throttling 给出了两种解决策略:

1. debounce的策略

1.1 延迟debounce

debounce,去抖动。策略是当事件被触发时,设定一个周期延迟执行动作,若期间又被触发,则重新设定周期,直到周期结束,执行动作。 这是debounce的基本思想。
延迟debounce,示意图:

1.2 前缘debounce

在后期进行优化又扩展了前缘debounce,即执行动作在前,然后设定周期,周期内有事件被触发,不执行动作,且周期重新设定。

为什么要这样呢?

试想第一种延迟debounce,我们本来想对用户输入的关键字,发起请求联想的频率降低,但是如果用户在我们设定的时间中,一直输入,导致的就是,用户一直看不到关键字,我们倒不如第一次输入的时候就发起一个请求,服务器返回结果,呈现给用户,然后后续用户的键入结束在继续请求)

前缘debounce,示意图

debounce的特点是当事件快速连续不断触发时,动作只会执行一次。 延迟debounce,是在周期结束时执行,前缘debounce,是在周期开始时执行。但当触发有间断,且间断大于我们设定的时间间隔时,动作就会有多次执行。

1.3 延迟debounce的实现

var debounce = (fn, wait) => {let timer, timeStamp=0; // timer and time stamplet context, args;let run = ()=>{timer= setTimeout(()=>{fn.apply(context,args);},wait);}let clean = () => {clearTimeout(timer);}return function(){context=this;args=arguments;let now = (new Date()).getTime();if(now-timeStamp < wait){console.log('reset',now);clean();  // clear running timer run();    // reset new timer from current time}else{console.log('set',now);run();    // last timer alreay executed, set a new timer}timeStamp=now;}
}

1.4 前缘debounce的实现


// 优化版: 定时器执行时,判断start time 是否向后推迟了,若是,设置延迟定时器
var debounce = (fn, wait) => {let timer, startTimeStamp=0;let context, args;let run = (timerInterval)=>{timer= setTimeout(()=>{let now = (new Date()).getTime();let interval=now-startTimeStampif(interval<timerInterval){ // the timer start time has been reset, so the interval is less than timerIntervalconsole.log('debounce reset',timerInterval-interval);startTimeStamp=now;run(timerInterval-interval);  // reset timer for left time }else{fn.apply(context,args);clearTimeout(timer);timer=null;}},timerInterval);}return function(){context=this;args=arguments;let now = (new Date()).getTime();startTimeStamp=now;if(!timer){console.log('debounce set',wait);run(wait);    // last timer alreay executed, set a new timer}}}

1.5 在前缘debounce基础上再添加一个是否立即执行的选项

// 增加前缘触发功能
var debounce = (fn, wait, immediate=false) => {let timer, startTimeStamp=0;let context, args;let run = (timerInterval)=>{timer= setTimeout(()=>{let now = (new Date()).getTime();let interval=now-startTimeStampif(interval<timerInterval){ // the timer start time has been reset,so the interval is less than timerIntervalconsole.log('debounce reset',timerInterval-interval);startTimeStamp=now;run(timerInterval-interval);  // reset timer for left time }else{if(!immediate){fn.apply(context,args);}clearTimeout(timer);timer=null;}},timerInterval);}return function(){context=this;args=arguments;let now = (new Date()).getTime();startTimeStamp=now; // set timer start timeif(!timer){console.log('debounce set',wait);if(immediate) {fn.apply(context,args);}run(wait);    // last timer alreay executed, set a new timer}}}

2. throttling节流的策略

throttling,节流的策略是,固定周期内,只执行一次动作,若有新事件触发,不执行。周期结束后,又有事件触发,开始新的周期。 节流策略也分前缘和延迟两种。
与debounce类似,延迟是指 周期结束后执行动作,前缘是指执行动作后再开始周期。

2.1 延迟throttling示意图:

2.2 前缘throttling示意图

2.3 延迟throttling的实现

// 简单版: 定时器期间,只执行最后一次操作
var throttling = (fn, wait) => {let timer;let context, args;let run = () => {timer=setTimeout(()=>{fn.apply(context,args);clearTimeout(timer);timer=null;},wait);}return function () {context=this;args=arguments;if(!timer){console.log("throttle, set");run();}else{console.log("throttle, ignore");}}}

2.4 前缘throttling的实现

/// 增加前缘
var throttling = (fn, wait, immediate) => {let timer, timeStamp=0;let context, args;let run = () => {timer=setTimeout(()=>{if(!immediate){fn.apply(context,args);}clearTimeout(timer);timer=null;},wait);}return function () {context=this;args=arguments;if(!timer){console.log("throttle, set");if(immediate){fn.apply(context,args);}run();}else{console.log("throttle, ignore");}}}

总结

debounce和throttling 各有特点,在不同 的场景要根据需求合理的选择策略。如果事件触发是高频但是有停顿时,可以选择debounce; 在事件连续不断高频触发时,只能选择throttling,因为debounce可能会导致动作只被执行一次,界面出现跳跃。

转载于:https://www.cnblogs.com/fe-linjin/p/10890101.html

性能优化之节流(throttling)与防抖(debounce)相关推荐

  1. 事件触发控制_前端性能优化:事件的节流throttle与防抖debounce

    scroll 事件是一个非常容易被反复触发的事件,另外,resize 事件.鼠标事件(比如 mousemove.mouseover 等).键盘事件(keyup.keydown 等)都存在被频繁触发的风 ...

  2. 性能优化之节流、防抖

    1. 防抖: 由于dom操作极其昂贵,所以尝试过多的dom操作有可能会将浏览器搞崩溃,比如onresize.onscroll这类事件操作: 为了解决这个问题,引出防抖的概念(某些代码不可以在没有间断的 ...

  3. 【前端帮帮忙】第7期 关于节流(throttle)和防抖(debounce)的理解

    节流和防抖在我们平时的项目中挺常用的,也是面试中经常会被提问的知识点,今天我们一起来学习一下. 节流 简单理解就是:控制函数每隔n秒执行一次. 作用 防止用户高频率的触发事件,刚好这个事件又需要处理大 ...

  4. JavaScript 函数节流 throttle 和防抖 debounce

    今天和别人聊到JavaScript函数的节流和防抖,发现自己对这两个的区别很是模糊,遂小小实践一下,在此记录,希望对需要的人有所帮助. 节流 - 频繁操作,间隔一定时间去做一件事 举例说明:假定时间间 ...

  5. 节流(Throttle)和防抖(Debounce)

    为啥要使用防抖和节流 在项目开发中,我们经常用到的滚动事件或者用户输入事件,都是一些高频事件,如果对这类事件触发的频率没有节制,就会加重浏览器和服务器的负担.节流和防抖目的就是减少事件触发的次数. 1 ...

  6. 【前端性能优化】不用 setTimeout 实现防抖

    相信大家都会使用 setTimeout 来实现防抖操作,但是如果有特殊情况,不能使用 setTimeout 怎么办呢,那么就可以使用以下方法来实现 /*** 防止多次点击按钮*/ function t ...

  7. 前端性能优化之防抖-debounce

    这周接到一个需求-给输入框做模糊匹配.这还不简单,监听input事件,取到输入值去调接口不就行了? 然而后端小哥说不行,这个接口的数据量非常大,这种方式调用接口的频率太高,而且用户输入时调用根本没有必 ...

  8. 关于前端性能优化问题,认识网页加载过程和防抖节流

    前端性能优化-网页加载过程.性能优化方法.防抖和节流 一.网页加载过程 1.加载资源的形式 2.加载资源的过程 3.渲染页面的过程 4.关于window.onload 和 DOMContentLoad ...

  9. JS高级 之 防抖 debounce - throttle 节流

    目录 一.防抖 debounce 1. 概念 2. 应用场景 3. 使用 underscore 实现防抖 01 - 代码 02 - 效果 4. 实现 01 - 基本实现 代码 效果 02 - 优化 = ...

最新文章

  1. Numpy入门教程:练习作业01
  2. 十二、八皇后问题(递归回溯)
  3. 因看不见而恐惧!企业亟需“看得见”威胁
  4. PC-lint 的代码实例
  5. linux软件包管理-rpm
  6. HTML5开发手机应用--viewport的作用--20150216
  7. IT人员健康信号之舌苔
  8. MyEclipse启动tomcat出现java.lang.OutOfMemoryError: PermGen space 的解决方案
  9. python生成词云_今天玩点啥:使用python生成微信好友地域分析、微信昵称、个性签名词云...
  10. Spring @Import注解配置类方法内部调用没有注入属性值的坑
  11. Token注解防止表单的重复提交
  12. Arduino笔记-使用RFID-RC522读取IC卡卡号
  13. 年度回顾 | 2019 年的 Apache Flink(文末有福利)
  14. Python数据挖掘框架
  15. 2020最新软件测试学习资料,全套源码无加密网盘下载
  16. 百度识图API教程一:使用百度api识别物体
  17. 《小鑫发现》之GraphQL框架Prisma
  18. python基础训练—元组
  19. Android 如何发送地理位置消息
  20. Vue报错:[WDS] Errors while compiling. Reload prevented

热门文章

  1. 洛谷P2058 海港(模拟,优先队列)
  2. 携手共进 智享未来丨美格智能2023年代理商合作伙伴大会成功举办
  3. 腾讯云php小程序,使用微信小程序和腾讯云实现直播功能
  4. 操作系统课程项目 OS project —— Pintos from Project 1 to Project 3
  5. 小米手机怎么录制视频 手机录制视频的方法
  6. 网卡和网卡的驱动程序
  7. maven私服deploy-405错误
  8. 报错:跨域问题解决 No ‘Access-Control-Allow-Origin‘ header is present on the requested resource.
  9. PTA 校选拔 7-10 宇航员的寻宝图(BFS)
  10. Vue对高德地图2.0的封装使用