JavaScript中的防抖与节流-图文版

JavaScript中的防抖与节流-图文版

01、防抖还是节流

防抖节流 目的都是避免一定时间内,大量重复的操作造成的性能损耗。因此原理也类似,都是阻止过多的事件执行,只保留一部分来执行。适用场景略有不同,也有交叉,动手练习一遍就懂了。

区别 防抖(Debounce) 节流(throttle)
描述 一定延迟时间内,连续事件只执行最后一次 一段固定时间内只执行一次
原理 只保留一个延时setTimeout()的执行器,后续新的替代旧的 判断时间间隔,在固定间隔时间内,只执行一次。
执行次数 只执行最后一次 执行首次、最后一次,或首次+最后一次
合适场景 连续操作只需要一次的,如变更内容提交到后端 连续操作定期执行的场景:连续的UI交互,如拖拽、滚动

02、什么是防抖(Debounce)?

按字面意思理解就是 防止抖动(Debounce /di'bauns/ 防抖动),本来只需要点击一次,结果手抖操作了很多次,重复执行就造成了额外的浪费。

JavaScript中的防抖与节流-图文版

🔸防抖函数的原理:在一定延迟时间内,连续触发的事件合并只执行 最后 一次。技术原理是用闭包保存一个延时执行函数setTimeout(func, delayTime)返回变量,只要延迟时间delayTime内新触发的执行器,就会代替旧执行器。

JavaScript中的防抖与节流-图文版

🪧实现代码

/******************************   防抖函数  ******************************/ //参数func:需要防抖的函数 //参数delayTime:延时时长,单位ms function debounce(func, delayTime) {     //用闭包路缓存延时器id     let timer;     return function (...args) {         if (timer)             clearTimeout(timer);  //清除-替换,把前浪拍死在沙滩上         timer = setTimeout(() => {             func.apply(this, args);         }, delayTime);     } } 

🟢适用场景

  • ✅ 提交按钮,避免重复点击提交数据,只执行最后一次。
  • ✅ 文本框输入的响应:如基于输入文本服务端联想查询,对输入内容的服务端验证等,防抖就可以避免没必要的请求,节约资源。
  • ✅ 连续触发的事件,如窗口的resize事件、窗口的滚动scroll事件,只处理最后一次。

🪧使用案例:滚动浏览器滚动条到末尾。

  • 如果不用防抖函数,scroll事件频繁触发,共触发了29次。
  • 加上防抖函数,同样的速度移动,只触发了最后一次。
//移动浏览器滚动条到末尾,无防抖 window.addEventListener('scroll', print); //执行了29次 //加上防抖,延迟300ms window.addEventListener('scroll', debounce(print, 300)); //执行了1次 let index = 0; function print() {     console.log(index++); } 

03、为何要节流(throttle)?

节流(throttle)字面意思就是节约流量(throttle /ˈθrɑːtl/ 节流阀),一个小朋友一分钟只能吃一勺饭,每分钟喂了30勺,喂得太快要么食物浪费了,要么被噎到。

🔸节流函数的原理:一定时间内只执行一次事件,在一段时间intervalTime内,不管触发了多少次事件(大于1)都只执行一次。

  • 因此首先需要判断间隔时间,是否在间隔时间内。
  • 具体执行的时机,可选择首次,也可以选择最后一次,或者首次+最后一次。

JavaScript中的防抖与节流-图文版

🪧实现代码:三种实现方式

  • 实现1:单位时间内执行第一次(立即执行),节流后面的,基于时间间隔判断。
  • 实现2:单位时间内执行第一次(延迟执行),节流后面的,基于延时函数setTimeout()
  • 实现3:执行首次+最后一次,节流中间的,比较综合全面的的实现方式!
// 实现1:单位时间内执行第一次(立即执行),节流后面的 function throttle(func, intervalTime = 100) {     let lastTime = 0;     return (...args) => {         let now = Date.now();         //首次调用会执行         if (now - intervalTime > lastTime) {             func.apply(this, args);             lastTime = now;         }     } } // 实现2:单位时间内执行第一次(延迟执行),节流后面的 const throttle2 = (func, intervalTime = 100) => {     // 定义falg,初试为true     let flag = true;     // 返回的函数是每次用户实际调用的节流函数     return (...args) => {         const ctx = this;         // 如果flag为true,则执行定时器         if (flag) {             setTimeout(() => {                 func.apply(ctx, args);                 // 函数执行完毕后=true;                 flag = true;             }, intervalTime);         }         //没执行完成前都为false         flag = false;     }; } // 实现3:执行首次+最后一次,节流中间的,比较综合的节流方式! function throttleMiddle(func, intervalTime = 100) {     let timer = null;     let startTime = 0;     return (...args) => {         const ctx = this;         const now = Date.now();         if (startTime && now < startTime + intervalTime) {             //替换前面的             clearTimeout(timer);             timer = setTimeout(() => {                 startTime = now;                 func.apply(ctx, args);             }, Math.max(intervalTime - (Date.now() - startTime), 0)); //剩余等候时间         } else { //每轮首次会执行,立即执行             startTime = now;             func.apply(ctx, args);         }     } } // 节流-函数扩展,使用的throttleMiddle版本 Function.prototype.throttle = function (intervalTime = 100) {     let func = this;     let startTime, timer = null;     //这里不能用箭头函数,会导致this污染     return function (...args) {         const ctx = this;         let now = Date.now();         if (startTime && now < startTime + intervalTime) {             clearTimeout(timer);             timer = setTimeout(() => {                 func.apply(this, args);                 startTime = now;             }, Math.max(intervalTime - (now - startTime), 0));         }         else {             startTime = now;             func.apply(ctx, args);         }     } } 

🟢适用场景

  • ✅ 定时秒杀、抽奖按钮,运行多次提交,避免太过频繁的提交把服务端搞崩了。
  • ✅ 连续的UI交互,如DOM拖拽,在窗口的resize事件、窗口的滚动scroll事件中更新UI,如果用防抖会有卡顿的现象,更适合用节流。

🪧使用案例:滚动浏览器滚动条到末尾。

  • 如果不用防抖函数,scroll事件频繁触发,共触发了29次。
  • 加上节流函数,同样的速度移动,执行了4次,间隔均匀。
//移动浏览器滚动条到末尾 window.addEventListener('scroll', print); //执行了29次 //加上节流,延迟300ms window.addEventListener('scroll', throttle(print, 300)); //执行了4次 let index = 0; function print() {     console.log(index++); } 

©️版权申明:版权所有@安木夕,本文内容仅供学习,欢迎指正、交流,转载请注明出处!原文编辑地址-语雀

发表评论

相关文章