防抖debounce
连续的多次动作内,只执行最后一次动作
⭐️ 设想下面场景:
-
有一个提交按钮,每次点击提交之后,就会向后台发起ajax请求
-
这样设计会有问题:用户在一定时间内多次点击提交,按钮就会像多次向后台发送请求!!
-
这时候,防抖就非常有用:用户在一定时间内无论多点击多少次提交,按钮只会提交一次
🔑 防抖有两种执行模式:
-
在一定动作内执行最后一次动作
-
在一定动作内只执行首次动作
流程图地址:https://processon.com/diagraming/6162fee37d9c0866512e839d
// 防抖函数 function debounce(func, wait = 300, immediately) { let timer, result // timer为定时器,result为传入的函数的返回值 let debounce = function (...args) { // 清楚定时器 if (timer) clearTimeout(timer) // 是否立即执行事件 if (immediately) { let callNow = !timer // 判断是否有无定时器 timer = setTimeout(() => { timer = null // 把定时器变量清空 }, wait) if (callNow) result = func.apply(this, args) } else { new Promise((resolve, reject) => { timer = setTimeout(() => { resolve(func.apply(this, args)) timer = null }, wait) }) } return result // 返回值 } // 终止防抖事件 debounce.cancel = function () { clearTimeout(timer) timer = null } // 返回 return debounce }
🏰 案例
应用场景:
- scroll事件滚动触发
- 搜索框输入查询
- 表单验证
- 按钮提交事件
- 浏览器窗口缩放,resize事件
-节流throttle
连续的多次动作内,在固定周期内,一个周期执行一次动作
⭐️ 还是举一个例子:
- 我现在有一个图片预览网站,里面有很多图片,需求是实现图片懒加载的监听
- 这里的问题是:每次拉动滚动条,就会触发事件去对比图片是否到达可视区域,触发非常频繁
- 这时候,节流就非常有用:在用户拉动滚动条的时候,我只在500ms这个周期内触发事件
🔑 节流有两种执行模式:
-
刚触发事件时会执行一次,后续周期会触发事件,最后一次事件不触发(顾头不顾尾)
-
刚触发事件时不执行,后续周期会触发事件,最后一次事件会触发(顾尾不顾头)
-
刚触发事件时会执行一次,后续周期会触发事件,最后一次事件会触发(顾头顾尾)
流程图地址:https://processon.com/diagraming/6163d0bae0b34d7c7da62cba
function throttle(func, wait, opt = {leading: true, trailing: true}) { let timer, // 定时器 old = 0 // 时间戳 return function (...args) { let now = new Date().valueOf() let later = () => { old = new Date().valueOf() // 更新时间戳 func.apply(this, args) timer = null } if(opt.leading === false) old = now // leading=false 永远不执行第一次 if (now - old > wait) { if (timer) { clearTimeout(timer) // 下面的定时器时间是不准的,有可能这个执行快 timer = null } func.apply(this, args) old = now } else if (!timer && opt.trailing !== false) { timer = setTimeout(later, wait) } } }
🏰 案例
- DOM元素拖拽
- 飞机每隔一段事件射击导弹
- 监听scroll滚动事件
- 计算鼠标移动的距离