首页IT科技js中防抖和节流(JS—节流与防抖)

js中防抖和节流(JS—节流与防抖)

时间2025-09-10 15:20:31分类IT科技浏览6054
导读:一、js防抖和节流 在进行窗口的resize、scroll、输出框内容校验等操纵的时候,如果事件处理函数调用的频率无限制,会加重浏览器的负担,导致用户体验非常之差。那么为了前端性能的优化也为了用户更好的体验,就可以采用防抖(debounce)和节流(throttle)的方式来到达这种效果,...

一                 、js防抖和节流

在进行窗口的resize                             、scroll        、输出框内容校验等操纵的时候                 ,如果事件处理函数调用的频率无限制                             ,会加重浏览器的负担        ,导致用户体验非常之差                   。那么为了前端性能的优化也为了用户更好的体验            ,就可以采用防抖(debounce)和节流(throttle)的方式来到达这种效果                             ,减少调用的频率                         。

二            、为什么滚动scroll                             、窗口resize等事件需要优化

滚动事件的应用很频繁:图片懒加载             、下滑自动加载数据        、侧边浮动导航栏等          。

在绑定scroll                            、resize事件时             ,但它发生的时候        ,它被触发的频率非常高                            ,间隔很近               。在日常开发的页面中                  ,事件中涉及到的大量的位置计算                  、DOM操作    、元素重绘等等这些都无法在下一个scroll事件出发前完成的情况下    ,浏览器会卡帧                         。

三                           、滚动和页面渲染前端性能优化的关系

为什么滚动需要优化?前面提到了事件中涉及到大量的位置计算                       、DOM操作、元素重绘等等                           ,这些又与页面的渲染有关系                       ,页面渲染又与前端的性能优化有关系?套娃一样,一层套着一层                      ,每一层都联系紧密                            ,每一层都如此平凡且重要              。

review一下前端的渲染和优化

web页面展示经历的步骤:js—style—layout—paint—composite    ,简单回顾一下                 ,在这里不做详细的介绍哦!

网页生成的时候                             ,至少会渲染(Layout+Paint)一次          。用户访问的过程中        ,还会不断重新的重排(reflow)和重绘(repaint)            ,用户scroll行为和resize行为会导致页面不断的进行重新渲染                             ,而且间隔频繁             ,容易造成浏览器卡帧                          。

四                      、防抖Debounce

(1)防抖Debounce情景

①有些场景事件触发的频率过高(mousemove onkeydown onkeyup onscroll)

②回调函数执行的频率过高也会有卡顿现象                  。 可以一段时间过后进行触发去除无用操作

(2)防抖原理

一定在事件触发 n 秒后才执行        ,如果在一个事件触发的 n 秒内又触发了这个事件                            ,以新的事件的时间为准                  ,n 秒后才执行    ,等触发事件 n 秒内不再触发事件才执行     。

官方解释:当持续触发事件时                           ,一定时间段内没有再触发事件                       ,事件处理函数才会执行一次,如果设定的时间到来之前                      ,又一次触发了事件                            ,就重新开始延时                           。

(3)防抖函数简单实现 //简单的防抖函数 function debounce(func, wait, immediate) { //定时器变量 var timeout; return function () { //每次触发scrolle    ,先清除定时器 clearTimeout(timeout); //指定多少秒后触发事件操作handler timeout = setTimeout(func, wait); }; }; //绑定在scrolle事件上的handler function handlerFunc() { console.log(Success); } //没采用防抖动 window.addEventListener(scroll, handlerFunc); //采用防抖动 window.addEventListener(scrolle, debounce(handlerFunc, 1000)); (4)防抖函数的演化过程 ①this event绑定问题 //以闭包的形式返回一个函数                 ,内部解决了this指向的问题                             ,event对象传递的问题 function debounce(func, wait) { var timeout; return function () { var context = this; var args = arguments; clearTimeout(timeout) timeout = setTimeout(function () { func.apply(context, args) }, wait); }; }; ②立即触发问题 //首次触发执行        ,再次触发以后开始执行防抖函数 //使用的时候不用重复执行这个函数            ,本身返回的函数才具有防抖功能 function debounce(func, wait, immediate) { var timeout; return function () { var context = this; var args = arguments; if(timeout) clearTimeout(timeout); // 是否在某一批事件中首次执行 if (immediate) { var callNow = !timeout; timeout = setTimeout(function() { timeout = null; func.apply(context, args) immediate = true; }, wait); if (callNow) { func.apply(context, args) } immediate = false; } else { timeout = setTimeout(function() { func.apply(context, args); immediate = true; }, wait); } } } ③返回值问题 function debounce(func, wait, immediate) { var timeout, result; return function () { var context = this, args = arguments; if (timeout) clearTimeout(timeout); if (immediate) { var callNow = !timeout; timeout = setTimeout(function() { result = func.apply(context, args) }, wait); if (callNow) result = func.apply(context, args); } else { timeout = setTimeout(function() { result = func.apply(context, args) }, wait); } return result; } } ④取消防抖                             ,添加cancel方法 function debounce(func, wait, immediate) { var timeout, result; function debounced () { var context = this, args = arguments; if (timeout) clearTimeout(timeout); if (immediate) { var callNow = !timeout; timeout = setTimeout(function() { result = func.apply(context, args) }, wait); if (callNow) result = func.apply(context, args); } else { timeout = setTimeout(function() { result = func.apply(context, args) }, wait); } return result; } debounced.cancel = function(){ cleatTimeout(timeout); timeout = null; } return debounced; } 五                            、节流Throttle (1)节流Throttle情景

①图片懒加载

②ajax数据请求加载

(2)节流原理

如果持续触发事件             ,每隔一段时间只执行一次函数                      。

官方解释:当持续触发事件时        ,保证一定时间段内只调用一次事件处理函数。

(3)节流实现—时间戳和定时器 时间戳 var throttle = function (func, delay) { var prev = Date.now() return function () { var context = this; var args = arguments; var now = Date.now(); if (now - prev >= delay) { func.apply(context, args); prev = Date.now(); } } } function handle() { console.log(Math.random()); } window.addEventListener(scroll, throttle(handle, 1000)); 定时器 var throttle = function (func, delay) { var timer = null; return function () { var context = this; var args = arguments; if (!timer) { timer = setTimeout(function () { func.apply(context, args); timer = null; }, delay); } } } function handle() { console.log(Math.random()); } window.addEventListener(scroll, throttle(handle, 1000)) (4)节流函数的演化过程 ①时间戳触发 //在开始触发时                            ,会立即执行一次; 如果最后一次没有超过 wait 值                  ,则不触发 function throttle(func, wait) { var context, args; var previous = 0; // 初始的时间点    ,也是关键的时间点 return function() { var now = +new Date(); context = this; args = arguments; if (now - previous > wait) { func.apply(context, args); previous = now; } } } ②定时器触发 //首次不会立即执行                           ,最后一次会执行                       ,和用时间戳的写法互补                       。 function throttle(func, wait){ var context, args, timeout; return function() { context = this; args = arguments; if(!timeout) { timeout = setTimeout(function(){ func.apply(context, args); timeout = null; }, wait); } } } ③结合时间戳和定时器 function throttle(func, wait) { var timer = null; var startTime = Date.now(); return function(){ var curTime = Date.now(); var remaining = wait-(curTime-startTime); var context = this; var args = arguments; clearTimeout(timer); if(remaining<=0){ func.apply(context, args); startTime = Date.now(); }else{ timer = setTimeout(fun, remaining); // 如果小于wait 保证在差值时间后执行 } } } 六    、节流防抖总结

防抖:原理是维护一个定时器,将很多个相同的操作合并成一个                          。规定在delay后触发函数                      ,如果在此之前触发函数                            ,则取消之前的计时重新计时    ,只有最后一次操作能被触发     。

节流:原理是判断是否达到一定的时间来触发事件                   。某个时间段内只能触发一次函数                         。

区别:防抖只会在最后一次事件后执行触发函数                 ,节流不管事件多么的频繁                             ,都会保证在规定时间段内触发事件函数          。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
win10怎样设置开机启动项(win10开机启动项设置教程) 企业网站免费推广的10种方法(轻松拓展市场覆盖,让您的网站更受欢迎)