小言_互联网的博客

简单入门到彻底搞懂防抖和节流

358人阅读  评论(0)

       今日头条出的题目是写一个防抖函数,,根据用户输入的词语,提交后端进行模糊查询,按输入次序显示服务器返回结果。
    
       原题目,面试官写的是注意防抖和次序。

      他的要求是: 比如输入非常快的提交了三次 a, b,c 三个字母。由于服务器响应慢,客户端已经提交c查询,但是服务器才返回的b的查询结果(这个用闭包,其实来闭包也有问题,典型如何处理异常)。
      

        面试官出的这道题的确很有代表性,前端开发中经常会遇到的问题,重复执行,表单重复提交,不管前后端开发都应该了解。这个题跟我大约2012年6月,腾讯网www.qq.com 首页改版上线,做的一个搜索模块很相似, 那时候在腾讯是我职业生涯中第一个前端开发工作。

        当时这个项目,填了几个坑:

         1.必须用原生javascript代码,腾讯网首页那时候可不让你引入jquery,引入一个大js这么大的访问量得浪费多少钱?:)
         2.就是层遮盖的问题,输入关键字 关键字弹层是摊在输入框下方,那时候搜索框下面有flash,一不小心就被flash盖住
   最坑的是还有飞来飞去的广告
         3.其次就是后端返回的智能提示元素个数不相同,还有可能不返回,元素个数不同,就需要代理机制,冒泡到上层处理
         4.另外就是css的问题,网页/图片/视频等栏目蓝色框是要覆盖的,各位看官仔细看,鼠标移动到“网页”下拉前下面是蓝色边框,移动过去后变没了。最先版本还记录用户鼠标从哪移的,点击了那个栏目,再跟关键词点击关联就跟复杂了。

         5. 因为这个作为一个模块,就是css动态加载,动态加载简单,加载进来能用,不跟其他人冲突,处理起来也琐碎。

         6.与分类栏目相关的关键词搜索,以及日志记录

         7.异常处理

          另外就是面试官说的那两个问题。我觉得最经典的就是防抖。虽然简单,但却经典,稍后介绍。

 

   我做项目的那会儿,不知道是否是学艺不精,不知道有防抖的概念,那 下面就来介绍一下防抖。下面的代码测试一下,就会浪费很多资源执行程序,这里仅是输出了console.log(),对资源消耗不大,如果数据库批量查询影响就很大了。运行下面的程序,打开浏览器,滚动滚动条或者放大缩小窗口,浏览器控制台就会输出一堆log。


  
  1. <html>
  2. <head>
  3. <meta charset="utf-8" />
  4. <style>
  5. body { font-size: 12px; height: 2000px;}
  6. </style>
  7. </head>
  8. <body>
  9. 访问页面,打开浏览器控制台,用鼠标滚动或者调整浏览器大小观看效果
  10. <script>
  11. //滚动
  12. window.onscroll = function(){
  13. console.log( '滚动条位置:' + document.body.scrollTop || document.documentElement.scrollTop)
  14. }
  15. //调整窗口大小
  16. window.onresize = () => {
  17. console.log( '窗口宽x高:' + window.innerWidth+ 'x'+ window.innerHeight)
  18. }
  19. </script>
  20. </body>
  21. </html>

函数防抖(debounce)

防抖函数:一个频繁触发的操作,在规定时间内,只让最后一次生效,前面的不生效。
  看防抖函数debounce(fn,delay),delay参数是1秒,1秒调用防抖函数不管多少次,只执行一次。

         防抖从字面的意思很好理解。典型的应用就是拍照,估计大家都有印象,不防抖的相机拍出来的照片有一堆重影。防抖就是让相机只拍一次。

上面项目需要防抖就是鼠标在 分类区域 移动的时候,如果用户从网页--》图片--》视频一下移动到音乐,只需要记录用户移动到了音乐即可。还有就是输入关键字非常快比如输入 菲律宾,实际查询菲律宾关键字就可以了。而不是输入“菲”查询一次“菲律”查询一次 “菲律宾”查询一次。

来一个最简单的例子,浏览器执行以下代码会发现console控制台输出很多次,但是计算资源是有限的,所以我们需要控制速度,这个好比游戏打怪,不等满血进度条完成,游戏无法开始。

上代码,看看防抖函数


  
  1. /* 函数防抖,
  2. @param fun 要防抖的函数名
  3. @param delay 防抖间隔时间
  4. */
  5. function debounce(fun, delay) {
  6. return (args) => {
  7. clearTimeout(fun.id) //清除定时器
  8. fun.id = setTimeout( ()=> {
  9. fun.call( this, args)
  10. }, delay)
  11. }
  12. }

经过上面的例子想必你也清楚了,什么是防抖,以及在前端如何防抖。对于后端那怎么防抖呢? 有兴趣的可以我在腾讯搜搜做积分系统的时候,写过的一篇文章,用memcache或者redis实际上实现的就是防抖

http://blog.sina.com.cn/s/blog_467eb8ca0100zmvb.html

那节流又是什么鬼东西呢? 

函数节流(throttle)

函数节流
一个函数执行一次后,只有大于设定的执行周期后才会执行第二次。
节流函数,throttle(fun,delay)参数是1秒,则是不管持续多长时间,每秒执行一次,且每秒只执行一次。

这个打个比方,就是一盆水,慢慢流出来,而不是哐 一下直接倒了。这个很简单可以看示例中函数节流的那部分代码。

在上面那个 //函数节流


  
  1. //函数节流
  2. function throttle(fun,delay){
  3. let valid = true
  4. return function(args) {
  5. if(!valid){
  6. //休息时间 暂不接客
  7. return false
  8. }
  9. // 工作时间,执行函数并且在间隔期内把状态位设为无效
  10. valid = false
  11. setTimeout( () => {
  12. fun.call( this, args)
  13. valid = true;
  14. }, delay)
  15. }
  16. }

在服务器端实现函数节流就很简单了,最好是放在异步执行,用sleep函数定时执行即可。

关于防抖和节流的函数 ,都写在下面了,大家在输入框快速输入字母,然后打开浏览器控制台,自行测试。


  
  1. <html>
  2. <head>
  3. <meta charset="utf-8" />
  4. <style>
  5. body { font-size: 12px;}
  6. span { width: 60px; height: 22px; display:inline-block;}
  7. </style>
  8. </head>
  9. <body>
  10. <span class="tip">无防抖测试 </span> <input id="text" />
  11. <br>
  12. <span class="tip">防抖测试 </span> <input id="input" />
  13. <br>
  14. <span class="tip">节流测试 </span> <input id="throttle" /> <br />
  15. </div>
  16. <script>
  17. //没有防抖请求
  18. function ajax(content) {
  19. console.log( 'ajax request data ' + content)
  20. }
  21. let input = document.getElementById( 'text')
  22. input.addEventListener( 'keyup', function (e) {
  23. ajax(e.target.value)
  24. })
  25. /*
  26. */
  27. /* 函数防抖,
  28. @param fun 要防抖的函数名
  29. @param delay 防抖间隔时间
  30. */
  31. function debounce(fun, delay) {
  32. return (args) => {
  33. clearTimeout(fun.id) //清除定时器
  34. fun.id = setTimeout( ()=> {
  35. fun.call( this, args)
  36. }, delay)
  37. }
  38. }
  39. let inputb = document.getElementById( 'input')
  40. let debounceAjax = debounce(ajax, 1000) //函数ajax加入防抖,间隔1秒
  41. inputb.addEventListener( 'keyup', function (e) {
  42. debounceAjax(e.target.value)
  43. })
  44. //函数节流
  45. function throttle(fun,delay){
  46. let valid = true
  47. return function(args) {
  48. if(!valid){
  49. //休息时间 暂不接客
  50. return false
  51. }
  52. // 工作时间,执行函数并且在间隔期内把状态位设为无效
  53. valid = false
  54. setTimeout( () => {
  55. fun.call( this, args)
  56. valid = true;
  57. }, delay)
  58. }
  59. }
  60. let throttleAjax = throttle(ajax, 1000)
  61. let inputc = document.getElementById( 'throttle')
  62. inputc.addEventListener( 'keyup', function(e) {
  63. throttleAjax(e.target.value)
  64. })
  65. </script>
  66. </body>
  67. </html>

总结

  • 函数防抖和函数节流都是防止某一时间频繁触发。
  • 函数防抖是某一段时间内只执行最后一次,而函数节流是小间隔时间执行一次。

结合应用场景

  • debounce 防抖 
    • window触发resize一次
    • 滚动操作记录最终状态
    • 鼠标不断点击触发,mousedown(单位时间内只触发一次)
    • 输入参数校验,只需要校验一次就好
  • throttle 节流
    • search搜索联想,用户在不断输入值时,节约请求资源
    • 监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断
    • 监听window 的resize多次
    • 计算鼠标移动距离
    • canvas画图
    • 射击游戏,单位时间点击按钮,单击鼠标发射一次子弹

 


转载:https://blog.csdn.net/robinhunan/article/details/106206316
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场