防抖和节流的实现

防抖

  • 触发函数后多长时间没再次触发,执行一次函数,如果再次触发重新开始计时
  • 常用于 key resize 等高频事件,输入框输入值时的本地缓存和异步请求
// 当页面发生滚动的时1s后执行函数
var timer = null;
window.addEventListener('scroll', function() {
	if(timer) clearTimeout(timer);
	timer = setTimeout(function() {
		console.log('我是a函数');
	}, 1000)
});

// 把函数抽出来
var timeout = null;
function debounce() {
	if(timeout) clearTimeout(timeout);
	timeout = setTimeout(function() {
		console.log('我是a函数');
	}, 1000)
}
window.addEventListener('scroll', debounce);

// 消除全局变量timeout
function debounce(fn, delay) {
	var timeout = null;
	return function() {
		if(timeout !== null) clearTimeout(timeout);
		timeout = setTimeout(fn, delay);
	}
}
function aa(){
    console.log('我是a函数')
}
window.addEventListener('scroll', debounce(aa, 1000));

// 消除局部变量timeout
function debounce(fun, delay) {
	return function() {
		let that = this;
		clearTimeout(fun.id)
		fun.id = setTimeout(function() {
			fun.call(that)
		}, delay)
	}
} 

window.addEventListener('scroll', debounce(aa, 1000));

// es6语法 减少局部变量
function debounce(fun, delay) {
	return function() {
		clearTimeout(fun.id)
		fun.id = setTimeout(() => {fun()}, delay)
	}
} 
window.addEventListener('scroll', debounce(aa, 1000));
  • input输入触发事件的例子,增加参数传递
//模拟一段ajax请求
function ajax(content) {
  console.log('ajax request ' + content)
}

function debounce(fun, delay) {
    return function (args) {
        let that = this
        let _args = args
        clearTimeout(fun.id)
        fun.id = setTimeout(function () {
            fun.call(that, _args)
        }, delay)
    }
}
    
let inputb = document.getElementById('debounce')

// 变量赋值
let debounceAjax = debounce(ajax, 500)

inputb.addEventListener('keyup', function (e) {
    debounceAjax(e.target.value)
})

节流

  • 规定多少时间内执行一次函数
  • 常用于click,scroll事件,监听是否滑动到底部加载更多
  • 节流实现的方式有两种时间戳和定时器
// 1. 时间戳的方式  特点:第一次触发 立即执行
var throttle = function(func, delay) {
	var prev = Date.now();
	return function() {
		var that = this;
		var args = arguments;
		var now = Date.now();
		if(now - prev >= delay) {
			func.apply(that, args);
			prev = Date.now();
		}
	}
}

function aa() {
	console.log('我是aa函数');
}
window.addEventListener('scroll', throttle(aa, 1000));

// 2. 定时器方式 特点:第一次不会立即执行,最后一次会延迟执行
var throttle = function(func, delay) {
	var timer = null;
	return function() {
		var that = this;
		var args = arguments;
		if(!timer) {
			timer = setTimeout(function() {
				func.apply(that, args);
				timer = null;
			}, delay);
		}
	}
}

function aa() {
	console.log('我是aa函数');
}
window.addEventListener('scroll', throttle(aa, 1000));
// 3. 时间戳+定时器  第一次会立即执行,最后一次会延迟执行
var throttle = function(func, delay) {
	var timer = null;
	var startTime = Date.now();
	return function() {
		var curTime = Date.now();
		var remaining = delay - (curTime - startTime);
		var that = this;
		var args = arguments;
		clearTimeout(timer);
		if(remaining <= 0) {
			func.apply(that, args);
			startTime = Date.now();
		} else {
			timer = setTimeout(func, remaining);
		}
	}
}

参考

掘金-7分钟理解JS的节流、防抖及使用场景
节流
好理解

posted @ 2018-12-11 15:49  bonly-ge  阅读(583)  评论(0编辑  收藏  举报