JS 函数节流和防抖
目的
函数防抖和函数节流:优化高频率执行js代码的一种手段,js中的一些事件如浏览器的resize、scroll,鼠标的mousemove、mouseover,input输入框的keypress等事件在触发时,会不断地调用绑定在事件上的回调函数,极大地浪费资源,降低前端性能。为了优化体验,需要对这类事件进行调用次数的限制。
简而言之,目的都是,降低回调执行频率。节省计算资源。
函数防抖
高频事件触发,n秒后只执行一次,如果n秒内再次被触发,则重新计算时间。
实现代码
// ES6 可立即执行版本(封装完成未测试,应该好用)
/**
* @param {fn}
* @param {delay} 时间间隔ms
* @param {isRun} 是否立即执行:true false
* @return {*}
*/
function debounce(fn, delay=100, isRun=false){
let timer = null;
return function(){
let args = arguments;
if(timer){
clearTimeout(timer)
}else{
isRun && fn.apply(this, args)
}
timer = setTimeout(()=>{
timer = null;
fn.apply(this, args)
}, delay)
}
}
// ES5 延时执行 版本
function debounce(fn, delay) {
var timer; // 维护一个 timer
return function () {
var _this = this; // 取debounce执行作用域的this
var args = arguments;
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(function () {
fn.apply(_this, args); // 用apply指向调用debounce的对象,相当于_this.fn(args);
}, delay);
};
}
// ES6 延时执行 版本(已测试,好用!!!)
function debounce (fn, delay=100){
let timer = null
return function () {
if(timer){
clearTimeout(timer)
}
timer = setTimeout(() => {
fn.apply(this, arguments) // 箭头函数的 this 和 arguments 取的是定义时外层的函数的
timer = null
}, delay);
}
}
测试用例
function testDebounce(e, content) {
console.log(e, content);
}
var testDebounceFn = debounce(testDebounce, 1000); // 防抖函数
document.onmousemove = function (e) {
testDebounceFn(e, 'debounce'); // 给防抖函数传参
}
函数节流
高频事件触发,n秒内只会执行一次。
实现代码
/**
* 函数节流 ES6 可立即执行版本(已测试,好用!!!)
* @param {Function} fn
* @param {number} delay 时间间隔ms
* @param {boolean} isRun 是否立即执行, 默认true
* @return {Function}
*/
function throttle(fn, delay=100, isRun=true){
let timer = null;
return function(){
let args = arguments;
if(!timer){
isRun && fn.apply(this, args)
timer = setTimeout(()=>{
timer = null;
isRun || fn.apply(this, args)
}, delay)
}
}
}
// ES5 延时执行 版本
function throttle(fn, delay) {
var timer;
return function () {
var _this = this;
var args = arguments;
if (timer) {
return;
}
timer = setTimeout(function () {
fn.apply(_this, args);
timer = null; // 在delay后执行完fn之后清空timer,此时timer为假,throttle触发可以进入计时器
}, delay)
}
}
// ES6 延时执行 版本(已测试,好用!!!)
function throttle(fn, delay=100){
let timer
return function() {
if(timer) {
return
}
timer = setTimeout(()=> {
fn.apply(this, arguments)
timer = null
}, delay)
}
}
测试用例
function testThrottle(e, content) {
console.log(e, content);
}
var testThrottleFn = throttle(testThrottle, 1000); // 节流函数
document.onmousemove = function (e) {
testThrottleFn(e, 'throttle'); // 给节流函数传参
}
补充:工具函数在Vue中的使用
methods: {
handleSearch(value) {...},
debounceHandleSearch: debounce(function(){this.handleSearch(...arguments)}, 1000),
// 因为在运行阶段,debounce函数中 `this` 的指向不是Vue实例,因此获取不到 `handleSearch`,所以在编写阶段“待执行函数”用一层函数包装后,立即执行,从而敲定该函数的运行环境。
}
常见应用场景
函数防抖的应用场景
- 搜索框搜索输入。只需用户最后一次输入完,再发送请求。
- 手机号、邮箱验证输入检测。
- 窗口大小Resize。只需窗口调整完成后,计算窗口大小。防止重复渲染。
函数节流的应用场景
- 滚动加载,加载更多或滚到底部监听
- 拖拽一个元素,要随时获取被拖拽元素的位置
- 高频点击提交,表单重复提交