先看看概念
函数防抖(debounce):
在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时;典型的案例就是输入搜索:输入结束后n秒才进行搜索请求,n秒内又输入的内容,就重新计时。
应用场景:
- search搜索联想,用户在不断输入值时,用防抖来节约请求资源。
- window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <button id="btn">第一次点击按钮立即执行 接下来 防抖</button> <button id="btn2">终止</button> </body> <script> var btn = document.getElementById('btn'); let b= 2 let f = debounce_2(sayHi,2000,true) btn.addEventListener('click',()=>{ f(b) }) btn2.addEventListener('click',()=>{ f.stop() }) // 防抖(非立即执行) function debounce_1(fn,wait){ let timer = null; return function(){ clearTimeout(timer); timer = setTimeout(() => { fn.apply(this,arguments) },wait) } } // 防抖立即执行 function debounce_2(fn,wait){ let time = null let flag = true return function (){ clearTimeout(time) if(flag){ fn.apply(this,arguments) flag = false } time = setTimeout(()=>{ flag = true },wait) } } // 防抖自定义第一次是否执行 function debounce_3(fn,wait,isImmediate = true){ let flag = true let time = null if(isImmediate){ if(flag){ return function (){ fn.apply(this,arguments) flag = false } } clearTimeout(time) time = setTimeout(()=>{ flag = true },wait) } return function (){ clearTimeout(time); time = setTimeout(() => { fn.apply(this,arguments) },wait) } } // 防抖自定义第一次是否执行 且可中断执行 function debounce_4(fn, wait = 500, isImmediate = false) { // 计时器 let timerId = null; // flag为真时立即执行 let flag = true; let resultFunc = null; if (isImmediate) { // 立即执行 // 例如:用户在输入框中输入字符,输入第一个字符时,立即执行一次 // 之后,最终间隔超过2秒后,才执行补全查询 resultFunc = function () { let context = this; clearTimeout(timerId); if (flag) { fn.apply(context, arguments); flag = false } timerId = setTimeout(() => { flag = true }, wait) } resultFunc.cancel = function () { // 例如,用户打字很快,然后输入完成后,未达到两秒钟就移动鼠标 // 此时输入框失去焦点,触发取消等待方法,立刻执行补全查询操作并显示结果出来 console.log("立即取消等待") clearTimeout(timerId); flag = true; } } else { // 不立即执行 // 例如:用户在输入框中输入字符,最终间隔超过2秒后,才执行补全查询 resultFunc = function () { let context = this; clearTimeout(timerId); timerId = setTimeout(() => { fn.apply(context, arguments) }, wait) } resultFunc.cancel = function () { console.log("立即取消等待"); clearTimeout(timerId); } } return resultFunc; } function sayHi(b) { console.log(b) console.log('防抖') } </script> </html>
函数节流(throttle):
规定在一个单位时间内,只能触发一次函数,如果这个单位时间内触发多次函数,只有一次生效; 典型的案例就是鼠标不断点击触发,规定在n秒内多次点击只有一次生效。
应用场景:
- 鼠标不断点击触发,mousedown(单位时间内只触发一次)
- 监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <button id="btn">第一次点击按钮立即执行 接下来 节流</button> <button id="btn2">终止</button> </body> <script> var btn = document.getElementById('btn'); let b= 2 let f = throttle_4(sayHi,3000) btn.addEventListener('click',()=>{ f(b) // throttle_3(sayHi,3000)(b) 不能这么写,因为这相当于每次都重新声明了这个节流函数 }) btn2.addEventListener('click',()=>{ f.stop() }) //节流(非立即执行) function throttle_1(fn,wait){ let flag = true; return function(){ if(flag == true){ flag = false var timer = setTimeout(() => { fn.apply(this,arguments) flag = true },wait) } } } //节流(立即执行) function throttle_2(fn,wait){ var flag = true; var timer = null; return function(){ if(flag) { fn.apply(this,arguments); flag = false; timer = setTimeout(() => { flag = true },wait) } } } //节流(自定义是否立即执行) function throttle_3(fn,wait = 500,isImmediate = false){ let flag = true; let timer = null; if(isImmediate){ return function(){ if(flag) { fn.apply(this,arguments); flag = false; timer = setTimeout(() => { flag = true },wait) } } } return function(){ if(flag == true){ flag = false var timer = setTimeout(() => { fn.apply(this,arguments) flag = true },wait) } } } //节流(自定义是否立即执行且可以中断) function throttle_4(fn, wait = 500, isImmediate = false) { let flag = true; let timer = null; let resultFunc = null; if (isImmediate) { // 立即执行 resultFunc = function () { if (flag) { fn.apply(this, arguments); flag = false; timer = setTimeout(() => { flag = true }, wait) } } resultFunc.cancel = function () { console.log("立即取消等待") clearTimeout(timer) } } else { // 不立即执行 resultFunc = function () { if (flag == true) { flag = false timer = setTimeout(() => { fn.apply(this, arguments) flag = true }, wait) } } resultFunc.cancel = function () { console.log("立即取消等待") clearTimeout(timer); flag = true; } } return resultFunc; } function sayHi(b) { console.log(b) console.log('节流') } </script> </html>