Js中的防抖与节流

  在实际开发中,我们经常需要绑定一些持续触发的事件,如resize、scroll,mousemove,input等,浏览器在默认情况下会对事件处理函数无限制的调用,这样就会加重浏览器的负载,导致用户体验很差,有些还会频繁向后台请求数据,对服务器造成不必要的压力有些情况下我们不需要事件持续触发过程中频繁的去执行事件处理函数,或者更希望把多次计算合并成一次,只操作一个精确点。对此,我们可以采用防抖(debounce)和节流(throttle)的方式来减少调用频率,同时又不影响实际效果。

函数防抖(debounce)

  函数防抖(debounce):当持续触发事件时,一定时间段内没有再触发事件,事件函数就执行一次,如果在该时间段内又触发了事件,就重新开始延时。也就是说当一个用户一直触发这个事件函数,且每次触发函数的间隔小于设定事件,那么防抖的情况下就执行一次。

  如上图,在持续触发scroll事件时,并不执行handle函数,当1000毫秒内没有触发scroll事件时,才会延时触发scroll事件

防抖函数使用场景:

  • 实时搜索框(根据输入框的数据发送ajax请求)(keyup)
  • 文本输入的验证(连续发送文字发送ajax请求验证,但只验证最后一次输入的内容)(input)
  • 判断scroll是否滚动到底部(scroll)

实现一个简单的debounce:

 1 // 防抖
 2         function debounce(fn, wait) {
 3             var timeout = null;
 4             return function () {
 5                 if (timeout !== null) clearTimeout(timeout);
 6                 timeout = setTimeout(fn, wait);
 7             }
 8         }
 9         // 处理函数
10         function handle() {
11             console.log(Math.random());
12         }
13         // 滚动事件
14         window.addEventListener(‘scroll‘, debounce(handle, 1000));

  当持续触发scroll事件时,事件处理函数handle只在停止滚动1000毫秒之后才会调用一次,也就是说在持续触发scroll事件的过程中,事件处理函数handle一直没有执行。

函数节流(throttle)

  函数节流(throttle):当持续触发事件时,保证一定时间段内只调用一次事件处理函数。节流通俗解释就比如我们水龙头放水,阀门一打开,水哗哗的往下流,秉着勤俭节约的优良传统美德,我们要把水龙头关小点,最好是如我们心意按照一定规律在某个时间间隔内一滴一滴的往下滴。

  如上图,持续触发scroll事件时,并不立即执行handle函数,每隔1000毫秒才会执行一次handle函数。

防抖函数使用场景:

  • 窗口调整(resize)
  • 页面滚动(scroll)
  • DOM元素的拖拽功能实现(mousemove)
  • 类似电商抢购商品时的疯狂点击抢购按钮(mousedown)

实现一个简单的throttle(时间戳版):

 1 var throttle = function (func,delay){
 2             var prev = Date.now();
 3             return function (){
 4                 var context = this;
 5                 var args = arguments;
 6                 var now = Date.now();
 7                 if(now - prev >= delay){
 8                     func.apply(context,args);
 9                     prev = Date.now();
10                 }
11             }
12         }
13         // 事件处理函数
14         function handle(){
15             console.log(Math.random());
16         }
17         // scroll事件
18         window.addEventListener(‘scroll‘,throttle(handle,1000));

  当高频事件触发时,第一次会立即执行(给scroll事件绑定函数与真正触发事件的间隔一般大于delay),而后再怎么频繁地触发事件,也都是每delay时间才执行一次。而当最后一次事件触发完毕后,事件也不会再被执行了 (最后一次触发事件与倒数第二次触发事件的间隔小于delay,为什么小于呢?因为大于就不叫高频了呀)。

另一个throttle例子(定时器版):

 1 var throttle = function (func, delay) {
 2             var timer = null;
 3             return function () {
 4                 var context = this;
 5                 var args = arguments;
 6                 if (!timer) {
 7                     timer = setTimeout(function () {
 8                         func.apply(context, args);
 9                         timer = null;
10                     }, delay);
11                 }
12             }
13         }
14
15         function handle() {
16             console.log(Math.random());
17         }
18         window.addEventListener(‘scroll‘, throttle(handle, 1000));

 

  当触发事件的时候,我们设置一个定时器,再次触发事件的时候,如果定时器存在,就不执行,直到delay时间后,定时器执行执行函数,并且清空定时器,这样就可以设置下个定时器。当第一次触发事件时,不会立即执行函数,而是在delay秒后才执行。而后再怎么频繁触发事件,也都是每delay时间才执行一次。当最后一次停止触发后,由于定时器的delay延迟,可能还会执行一次函数。

  节流中用时间戳或定时器都是可以的。更好的是结合时间戳与定时器使用,当第一次触发事件时马上执行事件处理函数,最后一次触发事件后也还会执行一次事件处理函数。

另一个throttle例子(时间戳+定时器版):

 1 var throttle = function (func, delay) {
 2             var timer = null;
 3             var startTime = Date.now();
 4             return function () {
 5                 var curTime = Date.now();
 6                 var remaining = delay - (curTime - startTime);
 7                 var context = this;
 8                 var args = arguments;
 9                 clearTimeout(timer);
10                 if (remaining <= 0) {
11                     func.apply(context, args);
12                     startTime = Date.now();
13                 } else {
14                     timer = setTimeout(func, remaining);
15                 }
16             }
17         }
18
19         function handle() {
20             console.log(Math.random());
21         }
22         window.addEventListener(‘scroll‘, throttle(handle, 1000));

  在节流函数内部使用开始时间startTime、当前时间curTime与delay来计算剩余时间remaining,当remaining<=0时表示该执行事件处理函数了(保证了第一次触发事件就能立即执行事件处理函数和每隔delay时间执行一次事件处理函数)。如果还没到时间的话就设定在remaining时间后再触发 (保证了最后一次触发事件后还能再执行一次事件处理函数)。当然在remaining这段时间中如果又一次触发事件,那么会取消当前的计时器,并重新计算一个remaining来判断当前状态。

总结:

  函数防抖:将几次操作合并为一此操作进行。原理是维护一个计时器,规定在delay时间后触发函数,但是在delay时间内再次触发的话,就会取消之前的计时器而重新设置。这样一来,只有最后一次操作能被触发。

  函数节流:使得一定时间内只触发一次函数。原理是通过判断是否到达一定时间来触发函数。

  区别: 函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,而函数防抖只是在最后一次事件后才触发一次函数。 比如在页面的无限加载场景下,我们需要用户在滚动页面时,每隔一段时间发一次 Ajax 请求,而不是在用户停下滚动页面操作时才去请求数据(常见的大型网站在进行数据访问时都是通过滚动页面每隔一段时间发送一个ajax进行数据请求)。这样的场景,就适用函数节流来实现。

参考链接:https://mp.weixin.qq.com/s/Vkshf-nEDwo2ODUJhxgzVA

原文地址:https://www.cnblogs.com/zsp-1064239893/p/11602479.html

时间: 2024-11-06 11:02:14

Js中的防抖与节流的相关文章

javascript中的防抖与节流。

1.什么是防抖?它有什么作用? 什么是防抖?相信行入门的小白,甚至做了一段时间的程序员也不太理解是什么意思,我也是听了公开课才了解一点,现在和大家分享一下我的理解! 函数防抖(debounce):当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发了事件,就重新开始延时.比如,在进行窗口的resize.scroll,输入框内容校验等操作时,如果事件处理函数调用的频率无限制,会加重浏览器的负担,导致用户体验非常糟糕,请求的次数多了浏览器会造成卡

来聊聊JavaScript中的防抖和节流

目录 JavaScript防抖和节流 问题还原 防抖 什么是防抖 使用场景 节流 什么是节流 使用场景 JavaScript防抖和节流 问题还原 我们先来通过代码把常见的问题还原: <html> <head> <meta charset="utf-8"> <title>问题演示</title> </head> <body> <script type="text/javascript&qu

闲聊前端性能----防抖、节流、重绘与回流。

在最近,小米9卖的特别火,在官方抢购的时候基本都是一点既空.这不禁让我想到了,官网是怎样控制顾客不停点击发起请求而不导致官网崩溃的呢?这由此引出了前端性能的优化中的----防抖和节流.在闲聊完后你就会发现有些时候在抢购商品的时候,你用鼠标在几秒钟不停的按了数十次,或许它仅仅是发送了你第一次点击抢购的那个请求.所以说 抢购时间内的第一次点击尤为关键! 下面来介绍一下什么是防抖!        防抖:任务频繁触发的情况下,只有任务触发的间隔超过制定的时间间隔的时候,任务才会被执行. 下面引用一下知乎

深入理解JS防抖与节流

参考博客:JS防抖和节流,感谢作者的用心分享 日常开发过程中,滚动事件做复杂计算频繁调用回调函数很可能会造成页面的卡顿,这时候我们更希望把多次计算合并成一次,只操作一个精确点,JS把这种方式称为debounce(防抖)和throttle(节流) 函数防抖 当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定时间到来之前,又触发了事件,就重新开始延时.也就是说当一个用户一直触发这个函数,且每次触发函数的间隔小于既定时间,那么防抖的情况下只会执行一次. function

JS的防抖和节流

数个月之前,在一次前端的性能优化中,接触到了JS中防抖和节流,一开始还不明白他们的应用在哪里,可后来才知道,这是前端中最基础的性能优化,在绑定 scroll .resize 这类事件时,当它发生时,它被触发的频次非常高,间隔很近.如果事件中涉及到大量的位置计算.DOM 操作.元素重绘等工作且这些工作无法在下一个 scroll 事件触发前完成,就会造成浏览器掉帧.加之用户鼠标滚动往往是连续的,就会持续触发 scroll 事件导致掉帧扩大.浏览器 CPU 使用率增加.用户体验受到影响.尤其是在涉及与

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

Hello 小伙伴们,如果觉得本文还不错,记得给个 star , 你们的 star 是我学习的动力!GitHub 地址 本文涉及知识点: 防抖与节流 重绘与回流 浏览器解析 URL DNS 域名解析 TCP 三次握手与四次挥手 浏览器渲染页面 在本文中,jsliang 会讲解通过自我探索后关于上述知识点的个人理解,如有纰漏.疏忽或者误解,欢迎各位小伙伴留言指出. 如果小伙伴对文章存有疑问,想快速得到回复. 或者小伙伴对 jsliang 个人的前端文档库感兴趣,也想将自己的前端知识整理出来. 欢迎

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

防抖和节流,主要是用来防止过于平凡的执行某个操作,如浏览器窗口变化执行某个操作,监听某个input输入框keyup变化,瀑布流布局时Y轴滚动,图片加载. js函数的防抖 经过一段事件才执行某个操作,如果时间内又执行了该操作则延长时间重新开始计算 /* 不做处理input触发keyup事件 */ /* 输入快的话会出现输出结果多次重复 */ window.onload = function () { let obj = document.getElementById('input') obj.ad

js的抖动及防抖和节流

 js的抖动 在 js 中 改变窗口大小 & 上下滚动滚动条 & 反复向输入框中输入内容 ... , 如果绑定了相应的事件 , 这些事件的触发频率非常高, 严重影响用户体验和服务器的性能 , 这种问题 在js中 就叫 js 的抖动 . 解决方法 : 防抖 & 节流  js的防抖 就是在 触发事件 中设置一个定时器来延迟 绑定事件 的生效 , 并且每次在 触发事件 中清除定时器 , 直到两次 触发事件 生效的间隔 能够触发定时器才会时 绑定事件 生效 (持续触发并不会对应函数 , 只

JS防抖与节流

日常开发过程中,滚动事件做复杂计算频繁调用回调函数很可能会造成页面的卡顿,这时候我们更希望把多次计算合并成一次,只操作一个精确点,JS把这种方式称为debounce(防抖)和throttle(节流) 函数防抖 当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定时间到来之前,又触发了事件,就重新开始延时.也就是说当一个用户一直触发这个函数,且每次触发函数的间隔小于既定时间,那么防抖的情况下只会执行一次. function debounce(fn, wait) { va