8

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

 1 year ago
source link: https://www.cnblogs.com/anding/p/16987336.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
image.png

01、防抖还是节流

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

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

02、什么是防抖(Debounce)?

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

image.png

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

image

🪧实现代码

/****************************** 防抖函数 ******************************///参数func:需要防抖的函数//参数delayTime:延时时长,单位msfunction 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次//加上防抖,延迟300mswindow.addEventListener('scroll', debounce(print, 300)); //执行了1次let index = 0;function print() { console.log(index++);}

03、为何要节流(throttle)?

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

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

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

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

  • 实现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次//加上节流,延迟300mswindow.addEventListener('scroll', throttle(print, 300)); //执行了4次let index = 0;function print() { console.log(index++);}

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK