一、函数防抖

  前端开发工作中,我们经常在一个事件发生后执行某个操作,比如鼠标移动时打印一些东西:

 window.addEventListener("mousemove", ()=>console.log(123));
//测试发现鼠标移动了1毫米,回调函数执行了将近10次,这种做法是非常耗费资源的。

  这就像电梯,如果一个电梯的设计是每进去一个人就立即关门,那么如果有10个人排队进会是怎么样呢?多耗电而且很危险。

  解决方法就是每进一个人都重新倒计时N秒再关门,这样只要每个人都在前一个人进去N秒之内进门,那么每进一个人,电梯都会重新计时N秒,所以它只会在最后一个人进门N秒之后再启动关门程序。

  这里有三个关键点:「事件是高频率发生的」、「在前一个发生后N秒内发生下一个」、「重新倒计时」

  函数防抖(debounce)就是以上解决方案的JavaScript实现,上面代码的改写思路是:每次事件发生后都只做两件事——「清除旧的计时器」、「设置新的计时器」

//重置计时器的函数
function debounce(func, ms){
let timer = null;
function reTimer(){
//重新计时
clearTimeout(timer)
timer = setTimeout(func, ms)
}
return reTimer;
}

//要执行的动作
function handle(){
console.log("--- do something ---")
}

//绑定事件:每次鼠标移动时,就会执行debounce返回的reTimer函数
window.addEventListener("mousemove", debounce(handle, 1000))

进一步分析

  前面说了,每次事件发生后都只做两件事——「清除旧的计时器」、「设置新的计时器」,那么为什么要在addEventListener里执行debounce函数呢?

  因为reTimer函数需要操作来自父级作用域的变量timer,而debounce函数就是为了创建这样一个作用域,使得每次执行reTimer函数时timer变量都是存在的。

  如果要求不使用debounce函数,我们就得把timer变量定义在addEventListener之前:

//重置倒计时
function reTimer(){
if(timer){
clearTimeout(timer)
}
timer = setTimeout(handle, 1000)
}

//事件处理
function handle(){
console.log("--- do something ---")
}

//事件绑定
let timer = null; //或者 window.timer = null
window.addEventListener("mousemove", reTimer)

  不过,相比使用debounce函数,这样做就不那么优雅了。

  addEventListener的目的是操作timer变量,而timer在debounce的作用域内,addEventListener访问不到,所以用debounce返回的reTimer去访问,这就是闭包了。

  防抖是让重复事件的处理函数只在最后一次发生时执行,而闭包只是一个更好的实现方案。

二、函数节流

  理解了函数防抖,函数节流也就好办了,我们只需要理解场景和方案。

  假如我们正在做一个输入框,要求每输入一个字符都调用一个API来查询数据,从而实现联想、自动补全等功能,然而我们的输入速度是很快的,可能还没等第一个字符的查询结果出来,第二个字符就已经敲进去了,所以我们需要让查询频率小一点,具体做法就是在输入的过程中,每隔N秒才查询一次。

  这里的关键点是:「事件是高频率发生的」、「在前一个发生后N秒内发生下一个」、「一个计时结束后再重新计时」

定时器实现节流

  节流函数(throttle)要做的就是:「确保一个计时器停止时再重新计时」

/*
* 节流函数生成器
* 传递事件处理函数和延迟时间
* 返回节流函数
*/
function throttleGen(fn, delay) {
let timer = null;
function throller() {
if (timer === null) {
timer = setTimeout(function () {
fn();
timer = null;
}, delay)
}
}

return throller;
}

//事件处理函数
function handle() {
console.log('-- do something --');
}


//绑定事件
window.addEventListener("mousemove", throttleGen(handle, 1000))

三、防抖和节流的对比

  用输入时执行动作的例子可以对比防抖和节流,防抖就是等最后一个字符输入完N秒之后再查询,而节流是在输入过程中每隔N秒查询一次。
  以上代码为了保持简单,刻意忽略了绑定上下文等操作,在实际编码过程中,只要稍加改动即可使用稳定可靠的防抖和节流函数,比如这样:

function debounce(fn, delay) {
let timer = null;
return function () {
var _this = this; //这里改了
clearTimeout(timer);
timer = setTimeout(function () {
fn.apply(_this); //这里改了
}, delay);
};
}

JS防抖和节流:原来如此简单的更多相关文章

  1. 因为它,我差点删库跑路:js防抖与节流

    前言 前端踩雷:短时间内重复提交导致数据重复. 对于前端大佬来说,防抖和节流的技术应用都是基本操作.对于"兼职"前端开发的来说,这些都是需要躺平的坑. 我们今天就来盘一盘js防抖与 ...

  2. 面试必问题:JS防抖与节流

    摘要:防抖与节流可谓是面试常见,其实很好理解,下面带你分分钟了解防抖与节流的基本思想与写法~ 本文分享自华为云社区<JS防抖与节流快速了解与应用>,作者:北极光之夜. . 一.速识防抖: ...

  3. 深入理解JS防抖与节流

    参考博客:JS防抖和节流,感谢作者的用心分享 日常开发过程中,滚动事件做复杂计算频繁调用回调函数很可能会造成页面的卡顿,这时候我们更希望把多次计算合并成一次,只操作一个精确点,JS把这种方式称为deb ...

  4. 2019 面试准备 - JS 防抖与节流 (超级 重要!!!!!)

    Hello 小伙伴们,如果觉得本文还不错,记得给个 star , 你们的 star 是我学习的动力!GitHub 地址 本文涉及知识点: 防抖与节流 重绘与回流 浏览器解析 URL DNS 域名解析 ...

  5. js防抖和节流

    今天在网上看到的,里面的内容非常多.说下我自己的理解. 所谓的防抖就是利用延时器来使你的最后一次操作执行.而节流是利用时间差的办法,每一段时间执行一次.下面是我的代码: 这段代码是右侧的小滑块跟随页面 ...

  6. js防抖和节流优化浏览器滚动条滚动到最下面时加载更多数据

    防抖和节流,主要是用来防止过于平凡的执行某个操作,如浏览器窗口变化执行某个操作,监听某个input输入框keyup变化,瀑布流布局时Y轴滚动,图片加载. js函数的防抖 经过一段事件才执行某个操作,如 ...

  7. 详谈js防抖和节流

    本文由小芭乐发表 0. 引入 首先举一个例子: 模拟在输入框输入后做ajax查询请求,没有加入防抖和节流的效果,这里附上完整可执行代码: <!DOCTYPE html> <html ...

  8. JS 防抖和节流

    防抖和节流 在处理高频事件,类似于window的resize或者scorll,或者input输入校验等操作时.如果直接执行事件处理器,会增大浏览器的负担,严重的直接卡死,用户体验非常不好. 面对这种情 ...

  9. js防抖与节流了解一下

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

随机推荐

  1. testlink数据表分析

    创建一个项目test node_types: 节点类型,这是一个固定的表 rights: 权限表,用户的操作权限 role_rights: 角色和权限关系表 roles: 角色表 testprojec ...

  2. Soul Android app 悬浮view以及帖子中view的联动刷新逆向分析

    Soul app是我司的竞品,对它的语音音乐播放同步联动的逻辑很感兴趣,于是就开启了一波逆向分析. 下面看代码,以及技术分析,直接步入正轨,哈哈. 我们根据https://github.com/xin ...

  3. 总结vscode调试vue,nodejs的各种方法

    之前写项目一直都是console.log()来调试的,浪费了很多时间,现在整理一下用vscode对nuxt(vue)前后端进行调试的方法 前端的调试 chrome+launch 使用chrome调试, ...

  4. Elasticsearch 集群部署

    本文部署环境 $ cat /etc/redhat-release CentOS Linux release (Core) 部署前系统优化 $ /etc/security/limits.conf roo ...

  5. search(8)- elastic4s-search-query模式

    上篇提过query模式除对记录的筛选之外还对符合条件的记录进行了评分,即与条件的相似匹配程度.我们把评分放在后面的博文中讨论,这篇我们只介绍query查询. 查询可以分为绝对值查询和全文查询:绝对值查 ...

  6. thinkphp5 csv格式导入导出(多数据处理)

    关于csv文件格式的导出导入个人见解 先上代码: <?php namespace think; class Csv { /** * 导出csv文件 * @param $list 数据源 * @p ...

  7. centos7与8的区别

    1.关于内核版本:RHEL8采用4.18.0-xRHEL7采用3.10-0-x 2 网络时间同步 RHEL8 只使用Chronyd,不支持NTP部署. RHEL7Chronyd与NTP两者都支持 3. ...

  8. log4j 详细解释

    2019独角兽企业重金招聘Python工程师标准>>> 虽然说log4j自己会用,但是还是觉得对配置文件还不是很熟悉,最近看了一个博客,感觉很不多,我提炼出自己的理解. 地址 案例我 ...

  9. Spring Developer Tools 源码分析:三、重启自动配置'

    接上文 Spring Developer Tools 源码分析:二.类路径监控,接下来看看前面提到的这些类是如何配置,如何启动的. spring-boot-devtools 使用了 Spring Bo ...

  10. Netty(二):数据在ChannelPipeline中的流经

    本文目的:测试数据在ChannelPipeline中的流经顺序及状态. 先看本文的测试代码: AdditionalInBoundHandler:入站处理器,不做任何处理,只是在响应读事件时打印用来观察 ...