这周接到一个需求-给输入框做模糊匹配。这还不简单,监听input事件,取到输入值去调接口不就行了? 然而后端小哥说不行,这个接口的数据量非常大,这种方式调用接口的频率太高,而且用户输入时调用根本没有必要,只要在用户停止输入的那一刻切调接口就行了。 唉?这个场景听起来怎么这么像防抖呢?

那到底什么是防抖呢? 大家一定见过那种左右两边中间放广告位的网站,在网页滚动时,广告位要保持在屏幕中间,就要不断地去计算位置,如果不做限制,在视觉上广告位就像在“抖”。防止这种情况,就叫防抖了!

防抖的原理是什么? 我一直觉得网上流传的例子非常形象:当我们在乘电梯时,如果这时有人过来,我们会出于礼貌一直按着开门按钮等待,等到这人进电梯了,刚准备关门时,发现又有人过来了!我们又要重复之前的操作,如果电梯空间无限大的话,我们就要一直等待了。。。当然人的耐心是有限的!所以我们规定了一个时间,比如10秒,如果10秒都没人来的话,就关电梯门。

用专业术语概括就是:在一定时间间隔内函数被触发多次,但只执行最后一次。

最简易版的代码实现:

function debounce(fn, delay) {let timer = null;return function() {const context = this;const args = arguments;if (timer) {clearTimeout(timer);timer = null;}timer = setTimeout(() => {fn.apply(context, args);}, delay);};
}
复制代码

fn是要进行防抖的函数,delay是设定的延时,debounce返回一个匿名函数,形成闭包,内部维护了一个私有变量timer。我们一直会触发的是这个返回的匿名函数,定时器会返回一个Id值赋给timer,如果在delay时间间隔内,匿名函数再次被触发,定时器都会被清除,然后重新开始计时。

当然简易版肯定不能满足日常的需求,比如可能需要第一次立即执行的,所以要稍做改动:

function debounce(fn, delay, immediate) {let timer = null;return function() {const context = this;const args = arguments;timer && clearTimeout(timer);if(immediate) {const doNow = !timer;timer = setTimeout(() => {timer = null;}, delay);doNow && fn.apply(context, args);}else {timer = setTimeout(() => {fn.apply(context, args);}, delay);}};
}
复制代码

比起简易版,多了个参数immediate来区分是否需要立即执行。其它与简易版几乎一致的逻辑,除了判断立即执行的地方:

const doNow = !timer;timer = setTimeout(() => {timer = null;
}, delay);doNow && fn.apply(context, args);
复制代码

doNow变量的值为!timer,只有!timer为true的情况下,才会执行fn函数。第一次执行时,timer的初始值为null,所以会立即执行fn。接下来非第一次执行的情况下,等待delay时间后才能再次触发执行fn。 注意!与简易版的区别,简易版是一定时间多次内触发,执行最后一次。而立即执行版是不会执行最后一次的,需要再次触发。

防抖的函数可能是有返回值,我们也要做兼容:

function debounce(fn, delay, immediate) {let timer = null;return function() {const context = this;const args = arguments;let result = undefined;timer && clearTimeout(timer);if (immediate) {const doNow = !timer;timer = setTimeout(() => {timer = null;}, delay);if (doNow) {result = fn.apply(context, args);} }else {timer = setTimeout(() => {fn.apply(context, args);}, delay);}return result;};
}
复制代码

但是这个实现方式有个缺点,因为除了第一次立即执行,其它情况都是在定时器中执行的,也就是异步执行,返回值会是undefined。

考虑到异步,我们也可以返回Promise:

function debounce(fn, delay, immediate) {let timer = null;return function() {const context = this;const args = arguments;return new Promise((resolve, reject) => {timer && clearTimeout(timer);if (immediate) {const doNow = !timer;timer = setTimeout(() => {timer = null;}, delay);doNow && resolve(fn.apply(context, args));}else {timer = setTimeout(() => {resolve(fn.apply(context, args));}, delay);}});};
}
复制代码

如此,只要fn被执行,那必定可以拿到返回值!这也是防抖的终极版了!

下次聊聊防抖的兄弟-前端性能优化之节流-throttle。

前端性能优化之防抖-debounce相关推荐

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

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

  2. 前端性能优化最佳实践(转)

    转载请注明: 转载自WEB前端开发(www.css119.com)-关注常见的WEB前端开发问题.最新的WEB前端开发技术(webApp开发.移动网站开发).最好的WEB前端开发工具和最全的WEB前端 ...

  3. 前端性能优化 七个方面

    前端性能优化的七大个方面 包括优化网络连接.减少请求数量. 减小资源大小.优化资源加载.减少重绘回流.使用性能更好的API和webpack构建优化 1. 优化网络连接 [使用CDN] CDN全称是Co ...

  4. 【前端性能】常见前端性能优化

    常见性能优化 前言 一.图片优化 1.雪碧图(图片精灵) 2.图片压缩 3.字体图标代替图片 4.webp图片 二.DOM优化 1.缓存DOM节点查找的结果 2.防抖和节流 3.事件代理 4.减少合并 ...

  5. 前端性能优化总结/懒加载、函数节流、优化dom操作、雪碧图、合并文件

    1.减少 HTTP 请求数量 在浏览器与服务器进行通信时,主要是通过 HTTP 进行通信.浏览器与服务器需要经过三次握手,每次握手需要花费大量时间.而且不同浏览器对资源文件并发请求数量有限(不同浏览器 ...

  6. 前端性能优化常用代码

    前端性能优化常用代码 为什么要做性能优化?性能优化到底有多重要? 网站的性能优化对于用户的留存率.转化率有很大的影响,所以对于前端开发来说性能优化能力也是重要的考察点. 性能优化的点非常的多,有的小伙 ...

  7. 暴肝!7000 字的前端性能优化总结 | 干货建议收藏

    为什么要做性能优化?性能优化到底有多重要? 网站的性能优化对于用户的留存率.转化率有很大的影响,所以对于前端开发来说性能优化能力也是重要的考察点. 性能优化的点非常的多,有的小伙伴觉得记起来非常的麻烦 ...

  8. 讲武德,你们要的7000字前端性能优化干货 ,来了

    为什么要做性能优化?性能优化到底有多重要? 网站的性能优化对于用户的留存率.转化率有很大的影响,所以对于前端开发来说性能优化能力也是重要的考察点. 性能优化的点非常的多,有的小伙伴觉得记起来非常的麻烦 ...

  9. 谈谈前端性能优化-面试版

    前言 当我们去面试的时候,很大概率会被面试官问这么一个问题:你有尝试过对项目做性能优化吗?或者你了解哪些性能优化的方法?听到这个问题的你可能是这样的: 似曾相识但又说不清楚,往往只能零散地说出那么几点 ...

最新文章

  1. Udacity机器人软件工程师课程笔记(三十二) - 卡尔曼滤波器 - 一维卡尔曼滤波器 - 多维卡尔曼滤波器 - 拓展卡尔曼滤波器(EKF)
  2. 2018-2019-1 20165337 《信息安全系统设计基础》第一周学习总结
  3. Linux下汇编语言学习笔记12 ---
  4. 开发者账号申请完多久可以用_苹果开发者从0到发布app到apple store
  5. mysql登录抓包_MySQL登录验证的抓包
  6. 北大OJ百练——4074:积水量(C语言)
  7. javascript 动态修改css样式
  8. 60usebean创建实例对象
  9. AR-关于几种特殊的收款方式说明
  10. [NOIP2010]关押罪犯(二分+二分图染色)
  11. Python序列循环移位的3种方法
  12. 华为P10的内存门和闪存门的检测方法
  13. Java应用开发的一条重要经验:先建立基础设施
  14. 基于热传导方程的高温作业专用服装设计(二)
  15. 数据库常用增删改查语句
  16. 聚焦新生代 戮默科技创造正向价值
  17. php插入图片适应屏幕,PHPExcel:如何在首页页眉中插入图片并将其放大以适应其内容?...
  18. 四旋翼自主飞行器设计方案
  19. C语言结合VBS脚本编写朗读小工具,做一个能够发音的C语言程序
  20. 南卡和漫步者蓝牙耳机哪个好?国产蓝牙耳机南卡和漫步者360度对比评测

热门文章

  1. boost::integer::gcd和boost::integer::lcm用法的测试程序
  2. Boost:测试bind <void>
  3. Boost:boost::bimaps::unordered_multiset_of的测试程序
  4. Boost:序列化之text_iarchive和text_oarchive
  5. Boost:libbz2.dll测试程序
  6. VTK:PolyData之Silhouette
  7. VTK:模型之FinanceFieldData
  8. 从C ++定义QML类型
  9. QML范围和命名分辨率
  10. C语言实现最短路径Bellman-Ford算法(附完整源码)