内容来源:SegmentFault社区

作者:nero

整理编辑:SegmentFault

曾经面试时候被问到过这个,年少的我一脸无知。。。

后来工作中遇到了一个场景:输入名称的同时去服务器校验名称是否重复,但发现之前的代码竟然都没做限制,输入一次发一次请求。简直忍不了,就在项目的utils里加上了防抖函数。正好做一个总结,加深印象。

函数防抖和节流,都是控制事件触发频率的方法。应用场景有很多,输入框持续输入,将输入内容远程校验、多次触发点击事件、onScroll等等。为了说明问题,假设一个场景:鼠标滑过一个div,触发onmousemove事件,它内部的文字会显示当前鼠标的坐标。

<style>#box {width: 1000px;height: 500px;background: #ccc;font-size: 40px;text-align: center;line-height: 500px;    }style>

<div id="box">div>

<script>const box = document.getElementById('box')  box.onmousemove = function (e) {    box.innerHTML = `${e.clientX}, ${e.clientY}`  }script>

效果是这样的:

在上边的场景下,我们不希望触发一次就执行一次,这就要用到防抖或节流。下面我们看一下它们能为我们做什么吧。

防抖

函数防抖,这里的抖动就是执行的意思,而一般的抖动都是持续的,多次的。假设函数持续多次执行,
我们希望让它冷静下来再执行。也就是当持续触发事件的时候,函数是完全不执行的,等最后一次触发结束的
一段时间之后,再去执行。先看一下效果:

分解一下需求:

  • 持续触发不执行

  • 不触发的一段时间之后再执行

那么怎么实现上述的目标呢?我们先看这一点:在不触发的一段时间之后再执行,那就需要个定时器呀,定时器里面调用我们要执行的函数,将arguments传入。封装一个函数,让持续触发的事件监听是我们封装的这个函数,将目标函数作为回调(func)传进去,等待一段时间过后执行目标函数

function debounce(func, delay) {  return function() {    setTimeout(() => {      func.apply(this, arguments)    }, delay)  }}

第二点实现了,再看第一点:持续触发不执行。我们先思考一下,是什么让我们的函数执行了呢?是上边的setTimeout。OK,那现在的问题就变成了持续触发,不能有setTimeout。这样直接在事件持续触发的时候,清掉定时器就好了。

function debounce(func, delay) {  let timeout  return function() {    clearTimeout(timeout) // 如果持续触发,那么就清除定时器,定时器的回调就不会执行。    timeout = setTimeout(() => {      func.apply(this, arguments)    }, delay)  }}

用法:

 box.onmousemove = debounce(function (e) {    box.innerHTML = `${e.clientX}, ${e.clientY}`  }, 1000)

节流:

节流的意思是让函数有节制地执行,而不是毫无节制的触发一次就执行一次。什么叫有节制呢?就是在一段时间内,只执行一次。同样,我们分解一下:

  • 持续触发并不会执行多次

  • 到一定时间再去执行

效果是这样的:

思考一下,持续触发,并不会执行,但是到时间了就会执行。抓取一个关键的点:就是执行的时机。

要做到控制执行的时机,我们可以通过一个开关,与定时器setTimeout结合完成。

函数执行的前提条件是开关打开,持续触发时,持续关闭开关,等到setTimeout到时间了,再把开关打开,函数就会执行了。我们看一下代码怎么实现:

  function throttle(func, deley) {    let run = true    return function () {      if (!run) {        return  // 如果开关关闭了,那就直接不执行下边的代码      }      run = false // 持续触发的话,run一直是false,就会停在上边的判断那里      setTimeout(() => {        func.apply(this, arguments)        run = true // 定时器到时间之后,会把开关打开,我们的函数就会被执行      }, deley)    }  }

调用的时候:

 box.onmousemove = throttle(function (e) {  box.innerHTML = `${e.clientX}, ${e.clientY}`}, 1000)

这样,就实现了节流,节流还可以用时间间隔去控制,就是记录上一次函数的执行时间,与当前时间作比较,如果当前时间与上次执行时间的时间差大于一个值,就执行。

说明一下节流时,后面操作中应该是因为run=false 所以才直接return,但是不是在return之前let run=ture直接覆盖掉之前的false

这里可以看一下throttle函数内部,和函数调用的时候。首先看函数内部,分解一下结构:

function throttle(func, deley) {    return function () {      // 执行func    }}

那调用时候呢?也分解一下:

throttle(function () { // 目标函数内容 }, 1000)

这里throttle函数执行的结果是其内部return的function的调用。也就是说鼠标经过的事件监听实际上是这个被return的function,不断持续触发的是它,而throttle函数只是提供了一个作用域,内部用闭包声明了一个run的开关变量,由于闭包的存在,run这个变量会一直存在不被销毁,而let run = true只在这个闭包(可以理解为作用域)内只声明了一次,但它不会被持续执行,所以return的函数内部的判断不会被它覆盖掉。根据打印结果可以看出,事实确实是如此:

总结:

防抖和节流巧妙地用了setTimeout,来控制函数执行的时机,优点很明显,可以节约性能,不至于多次触发复杂的业务逻辑而造成页面卡顿。


欢迎关注 SegmentFault 微信公众号 :)

timertask run函数未执行_函数的防抖和节流是个啥???相关推荐

  1. timertask run函数未执行_图执行模式下的 TensorFlow 2

    文 /  李锡涵,Google Developers Expert 本文节选自<简单粗暴 TensorFlow 2.0> 尽管 TensorFlow 2 建议以即时执行模式(Eager E ...

  2. Python 函数的执行流程-函数递归-匿名函数-生成器

    1 函数的执行流程 函数的执行需要对函数进行压栈的,什么是压栈呢,简而言之就是在函数执行时在栈中创建栈帧存放需要变量以及指针的意思.具体涉及的知识非常多,这里就已一个Python脚本简单进行分析. 当 ...

  3. setwindowshookex回调函数不执行_不一样的“悬停几秒后执行函数”?一个开源工具函数,请注意查收...

    大家好,我是 vortesnail. 前言: 最近这几个星期,一直都在维护自己的基于 React 的开源播放器组件,以为功能基本都差不多了,却忽视了播放器一个很重要的功能:鼠标悬停在视频播放界面时,在 ...

  4. js执行oracle函数吗,执行javascript函数

    JS--函数 JavaScript 函数语法 函数就是包裹在花括号中的代码块,前面使用了关键词 function: function 函数名([参数]){ 执行的代码: } 当调用该函数时,会执行函数 ...

  5. php脚本函数,PHP执行系统命令函数实例讲解

    命令注入 命令注入(Command Injection),对一些函数的参数没有做过滤或过滤不严导致的,可以执行系统或者应用指令(CMD命令或者 bash 命令)的一种注入攻击手段. 常见的执行系统命令 ...

  6. filter函数的用法_函数周期表丨筛选丨表丨CALCULATETABLE

    CALCULATETABLE函数 CALCULATETABLE函数属于"筛选"类函数,隶属于"表函数". 某种意义上来说,CALCULATETABLE函数其实就 ...

  7. matlab watershed函数简单实现_函数指针方法实现简单状态机(附代码)

    之前写过一篇状态机的实用文章,很多朋友说有几个地方有点难度不易理解,今天给大家换种简单写法,使用函数指针的方法实现状态机. 状态机简介 有限状态机FSM是有限个状态及在这些状态之间的转移和动作等行为的 ...

  8. ostream作为函数返回值_函数的调用(一)

    函数作为计算机代码的一种抽象方式,它的作用不言而喻! 原文链接 认识函数: 定义:函数是一段代码的表示,是一段具有特定功能的,可重用的语句组 函数是一种功能的抽象,一般函数表达特定功能 两个作用:降低 ...

  9. python-return_全局局部变量_函数名用法_函数嵌套

    函数 1. return 返回值 作用: ​ 自定义函数的返回值,return 可以把值返回到函数的调用处 ​ return + 六大标准数据类型 , 还有类和对象,函数 ​ 如果不定义return ...

最新文章

  1. 图表+笔记-python语言-第5章:数字/5.11 位操作
  2. Error in ** : incorrect number of dimensions
  3. MySQL数据库操作(DDL)
  4. 关于“豪猪”,你理解的透彻吗?【Hystrix是个什么玩意儿】
  5. Metro UI 菜单(Winform)
  6. python canopen_Python canopener包_程序模块 - PyPI - Python中文网
  7. How-to: Build VPP FD.IO development environment with Mellanox DPDK PMD.
  8. SQL Server 2005 Express数据库为“只读”
  9. [Java] 蓝桥杯PREV-5 历届试题 错误票据
  10. mysql 字节流_字节流至缓冲流
  11. solr4.2增量索引之同步(修改,删除,新增)
  12. 一篇好文之Android文本软键盘全解
  13. 惠普1020打印机查看已打印页数
  14. python 过采样算法_类不平衡数据分类准确率的提升算法smote过采样方法
  15. 智能陈桥输入法软件测试,智能陈桥五笔输入法
  16. oracle px execute reply,关于昨天的PX Deq: Execute Reply重新开贴请教
  17. python一入深似海-模块化编程-钢铁侠战甲(二)
  18. 多元线性回归哑变量设置方法
  19. 【R】R语言指定包安装目录
  20. Windons10安装RDKit

热门文章

  1. 安顺计算机二级考试,安顺市2020年3月计算机二级报名时间|网上报名入口【12月18日9:00开通】...
  2. [OS复习]设备管理3
  3. ArcGis10安装步骤
  4. WINDOWS键盘事件的挂钩监控原理及其应用技术
  5. 前端优化方案-JavaScript 优化方案 收藏 此文于2010-06-04被推荐到CSDN首页
  6. 计算机网络第四章-网络层复习笔记
  7. BUUCTF-Reverse:xor(涉及异或脚本编写)
  8. Java 重定位 —— redirect:
  9. 「 每日一练,快乐水题 」191. 位1的个数
  10. 都2021年了,不会还有人连深度学习还不了解吧(六)-- Padding篇