节流和防抖
防抖和节流:限制函数的执行次数;
(1)节流:如果你持续触发事件,每隔一段时间,只执行一次事件;
应用场景
DOM元素的拖拽功能实现
射击游戏
计算鼠标移动的距离
监听scroll滚动事件
利用时间戳进行节流的方式
<body>
<div id="box"></div>
<button id="btn">点击取消节流</button>
<script>
// 第一次触发,最后不会被调用触发的函数
// 不顾头 顾尾
let box = document.getElementById('box');
let btn = document.getElementById('btn');
function throttle(func, await) {
let old = 0;
let context,args;
return function() {
context = this;
args = arguments;
// 得到现在的时间戳
let now = new Date().getTime();
if(now - old > await) {
func.apply(context, args)
old = now
}
}
}
function doSomething() {
console.log('执行了这句代码');
}
box.onmousemove = throttle(doSomething, 3000)
</script>
</body>
利用定时器进行节流
<script>
let box = document.getElementById('box');
let btn = document.getElementById('btn');
function throttle(func, await) {
let context,args, timer;
return function() {
context = this;
args = arguments;
if(!timer) {
timer = setTimeout(function() {
func.apply(context, args)
timer = null;
},await)
}
}
}
function doSomething() {
console.log('执行了这句代码');
}
box.onmousemove = throttle(doSomething, 3000)
</script>
第一次执行,最后一次也会执行
<script>
// 第一次会执行,最后一次也会执行
let box = document.getElementById('box');
let btn = document.getElementById('btn');
function throttle(func, await, options) {
let context,args, timer;
let old = 0;
if(!options) options ={}
return function() {
context = this;
args = arguments;
let now = new Date().valueOf();
if( options.leading === false && !old) {
old = now;
}
if(now - old > await) {
if(timer) {
clearTimeout(timer)
timer = null
}
func.apply(context, args)
old = now
}else if(!timer && options.trailing !== false) {
timer = setTimeout(function() {
func.apply(context, args)
timer = null;
old = new Date().valueOf()
},await)
}
}
}
function doSomething() {
console.log('执行了这句代码');
}
box.onmousemove = throttle(doSomething, 3000)
</script>
(2)防抖:事件响应函数在一段时机后才执行,如果在这段时间内再次调用,则重新计算执行时间;当预定的时间内没有再次调用该函数,则执行函数;
应用场景
scroll事件滚动触发
搜索框输入查询
表单提交
按钮的点击或者提交
浏览器窗口缩放事件即resize事件
一个简单版的防抖函数(主要是实现了再一定时间内再次去触发事件的时候,函数是不会执行的,只有超过了这个时间,函数才会执行)
<script>
let box = document.getElementById('box');
function debounce(func, await) {
let timer;
return function() {
if(timer) clearInterval(timer)
timer = setTimeout(function() {
func();
}, await)
}
}
function doSomething(e){
console.log('我是需要执行的函数');
}
box.onmousemove = debounce(doSomething, 300);
</script>
第一次优化(主要处理了this指向以及事件对象的问题)
<script>
// 解决this执行的问题,以及当函数中传递了参数,参数接收的问题
let box = document.getElementById('box');
function debounce(func, await) {
let timer;
return function() {
let args = arguments;
let context = this;
if(timer) clearInterval(timer)
timer = setTimeout(function() {
func.apply(context, args);
}, await)
}
}
function doSomething(e){
console.log('我是需要执行的函数', e,this);//通过打印发现this的指向以及事件对象全部都有了,
}
box.onmousemove = debounce(doSomething, 300);
</script>
第二次优化(当存在第三个参数即立即执行)
<script>
// 当存在第三个参数,即立即执行
let box = document.getElementById('box');
function debounce(func, await, immediate) {
let timer;
return function() {
let args = arguments;
let context = this;
if(timer) clearInterval(timer)
// 当第三个参数存在的时候,即为立即执行
// 这里的逻辑为:定义一个变量,当这个变量为真的时候,则为立即执行,不然的话,就不执行,此变量受timer控制
if(immediate) {
let now = !timer;
timer = setTimeout(function() {
timer = null;
}, await)
if(now) func.apply(context, args);
}else {
timer = setTimeout(function() {
func.apply(context, args);
}, await)
}
}
}
function doSomething(e){
console.log('我是需要执行的函数', e,this);//通过打印发现this的指向以及事件对象全部都有了,
}
box.onmousemove = debounce(doSomething, 300, true);
</script>
第三次优化(防抖函数中有返回值以及取消防抖)
<script>
// 当存在第三个参数,即立即执行
let box = document.getElementById('box');
let btn = document.getElementById('btn')
function debounce(func, await, immediate) {
let timer,result;
let resultFunction = function() {
let args = arguments;
let context = this;
if(timer) clearInterval(timer)
// 当第三个参数存在的时候,即为立即执行
// 这里的逻辑为:定义一个变量,当这个变量为真的时候,则为立即执行,不然的话,就不执行,此变量受timer控制
if(immediate) {
let now = !timer;
timer = setTimeout(function() {
timer = null;
}, await)
if(now) result = func.apply(context, args);
}else {
timer = setTimeout(function() {
result = func.apply(context, args);
}, await)
}
return result
}
resultFunction.cancel = function(){
clearTimeout(timer);
timer = null;
}
return resultFunction
}
function doSomething(e){
console.log('我是需要执行的函数', e,this);//通过打印发现this的指向以及事件对象全部都有了,
return '我是内容区域'
}
let debounceFun = debounce(doSomething, 3000)
btn.onclick = function () {
debounceFun.cancel();
}
box.onmousemove = debounceFun;
</script>
|