美文网首页
防抖与节流

防抖与节流

作者: 刘程源 | 来源:发表于2019-08-08 00:20 被阅读0次

    debounce/防抖:抖完以后在执行
    等待-执行

    throttle/节流:按计划"节制"执行(我会直接翻译成节制)
    执行-等待

    debounce

    想象一下,使用单反或者手机拍照,总会有一个对焦的过程,举个冷笑话,如果你的"帕金森"正好发作,如何才能拍出好照片?很简单啊,病好了再拍,这就是防抖的基础原理
    想象一下,我们跑步的时候看东西(肯定没啥问题),但如果运动+摄像,那画面应该很难接受,为什么用眼直接看没有问题呢?因为眼球会根据情况进行抖动,简称共振,大脑会根据当时的情况进行处理和分析,简称脑补
    如果大脑不够用怎么办?软件不够硬件凑,"鸡头防抖"尝试下
    如果没有"鸡头"呢?青蛙的动态视觉,蝙蝠的超声波,苍蝇的复眼
    .....

    防抖是光学处理上必不可少的处理,debounce的中文翻译即防抖,毫无疑问这里引用的是防抖的概念,这种跨行引用,本身也没有严格的规范与描述或者唯一的解决方案

    吐槽1
    针对光学防抖,还有补抖的概念,所以我对防抖的理解依然处于达到用户预期结果,而优化性能,只能说是顺带

    吐槽2
    以下说的防抖解决方案,可以直接理解为高频或ajax重复提交解决方案,通用的部分被称为debounce/throttle,但在某些特殊情况下又会有些变种

    throttle -> requestAnimationFrame

    控制自己,注意节制
    所谓的节制即单位时间(n秒)内,最多做有限次(m次)

    节制对于产品需求更为常见
    比如各种api访问限制,1小时只可访问3000条,1天不可超过10w次等等,很显然这些都是后端处理
    对于前端来讲,使用节制会产生"副作用",即后续请求可能会拒绝执行,除了产品需求,他被使用的地方非常有限,仅限于用户"被动"提交的高频交互

    • 产品需求
      做个一分钟点击某处次数最多或者打鼹鼠的游戏,如果用户没有操作节制,按键精灵第一
    • scroll
      滚动加载(也可以防抖解决,效果不如节流好)
    • mousemove
      反向例子,真用到mousemove的话,比如轨迹划线,只会认为mousemove自带节制,使轨迹不连贯,还需要特殊处理
    • 卡顿操作
      常见动画,canvas,图标等需求,描述为卡顿,专业点叫丢帧,原因是reflow与repaint
      毕竟像内存溢出,如
    for(var i=0,arr = [];i<3600*1000*1000;i++)arr.push(i)
    

    或复杂逻辑,如

    var now = Date.now();while(Date.now() - now < 3*1000){}console.log(1);
    

    正常是不会存在前端的

    而所谓的卡顿,即函数每次执行时间超过1000/fps,一般出现情况是一帧内多次执行(高频)某函数引起了渲染超过16ms(默认),而对于某函数就是需要16ms,做优化重写吧

    而在下一帧执行函数即requestAnimationFrame,所以throttle的使用并不多见

    1.抖是什么

    由用户在结果返回前产生的非预期操对结果产生影响的因素

    以上为模仿官方的描述,对于前端主要针对ajax(spa)其实就是

    • 快速点击(spa/get)

    用户原因:
    服务器反应慢误判
    单击与双击的惯性操作
    客户反悔快速切换频道
    .....

    后端原因:
    服务器慢
    后台为了性能,不提供分页描述,只提供内容数据(老观念)
    ......

    注:
    如果是后端渲染的get,会直接修改url,无论多慢,都是以最后一次操作为准,绝对不会有显示预期问题

    • 重复提交(post)

    用户原因:
    同get

    后端原因:
    没有做重复校验(依赖前端校验)
    数据库没有唯一约束(正好赶上数据第一条添加中,第二条通过了)
    ......

    • 其他高频触发事件
      略,一般会有明显的需求描述

    2.解决方案

    快速点击(spa/get)

    以搜索框提示为例,根据输入内容获取相关索引,如果不做处理,在"帕金森"发作时,同一时间多次提交后台,可能会引起内容与关键字比匹配的bug

    1.防抖 - 抖完在执行
    通用解决方案,即n秒内只执行1次,且只执行最后一次,即抖完
    如淘宝搜索框

    1.png
    对后台的请求只执行了两条

    实现关键点

    • setTimeout
    • clearTimeout

    注:
    这是最通用的方法,实际上他并没有真正的解决问题,只能降低概率,能提的也只有减少请求次数
    比如当第一次请求完成时间400ms,第二次请求为40ms,debounce设置30ms,中间间隔10ms,那显然,第二次请求在第一次请求完成前就已经完成,例子中的问题依然没有解决

    2.防抖 - 抖动即取消
    实际上,异步防抖,必须将前一个未完成的请求中断,即抖动即取消,也可以这么说
    如果函数不可以取消,抖完了在执行
    如果函数可以取消,抖动即取消(上一个未完成的函数)

    丢张度娘的搜索,理解下


    2.png

    异步处理(多线程,事务,原子操作)怎么理解都行,或许他并不是通常的防抖,不过在ajax这种例子里,1,2是要混用的

    实现关键点

    • abort

    注:
    如果把防抖的时间,设置为ajax执行完成,那他就变成了节流

    3.节制 - 缓存
    已查询过的索引是否也可以缓存?按需求来,get幂等(一般可以缓存)
    节制 + 缓存
    即如果在节制期内,查询缓存

    实现关键

    • memoize

    重复提交(post)

    以新增表单为例,对没有处理的新增按钮多次点击,可能会引起后台多条数据的添加

    4.节制 - 单例
    表单提交期间,button[disabled]或全局转菊花

    节制 + 上一个未完成

    这是一种特殊的节流,依然可以理解为事务操作,在前一个操作未反馈前,不应该在发送请求

    当然,也可以这么理解,把throttle的时间参数转换为函数

    批量加载

    首次页面打开,需要多个ajax初始化,如何优化

    5.防抖 - 合并
    单位时间内请求的ajax进行合并,而后通过超级接口获取数据

    合并才是防抖的精髓,相机如何自动防抖?在用户点击执行按钮时,连续拍摄多张,而后进行合成即可,人眼也是(脑补)

    完结

    对我来讲,第一次使用debounce/throttle,是在某工具类(lodash/underscore或其他系列_)中,没有中文翻译,直接正面用,翻译直接是防反跳/节流阀,也叫等待-执行或执行-等待,引入的例子是电梯,就知识点将他归为高频处理/重复提交,不知道是哪路神仙大拿的经典翻译,果然十分形象,这里完全是以防抖与节流的名义,描述如何处理常见的ajax问题

    在某些早期库中,会用一个函数封装debounce/throttle,并在最后传递boolean以确定是先执行还是后执行,这就是为什么我会习惯称debounce为等待-执行,throttle为执行-等待

    相关文章

      网友评论

          本文标题:防抖与节流

          本文链接:https://www.haomeiwen.com/subject/mwyndctx.html