函数去抖
函数去抖的意思是说当调用该函数n毫秒后,才会执行该函数,若在这n毫秒内又调用此函数则将重新计算执行时间。
function debounce(method,delay,arguments){//method为需要执行的函数,delay是延时时间(毫秒),arguments是method函数需要传递的参数
var timer=null;
return function(){
var context=this, args=arguments;
clearTimeout(timer);
timer=setTimeout(function(){
method.apply(context,args);
},delay);
}
}
函数节流
存在一种情况是:假如你不断地调用该函数,利用函数去抖,那么该函数将永远无法执行,因此引入函数节流
函数节流的原理是函数预先设定一个执行周期,当调用动作的时刻大于等于执行周期则执行该动作,则立即执行该函数
var throttle = function(fn, arguments,delay, mustRunDelay){
var timer = null;
var t_start = new Date();
return function(){
var context = this, args = arguments, t_curr = new Date();
clearTimeout(timer);
if(!t_start){
t_start = t_curr;
}
if(t_curr - t_start >= mustRunDelay){
fn.apply(context, args);
t_start = t_curr;
}
else {
timer = setTimeout(function(){
fn.apply(context, args);
}, delay);
}
};
};
以上是函数节流和函数去抖的基本思路,总体来看是利用闭包的想法,自己的理解是return中返回的是函数,这个函数会用到之前所定义的timer、t_start,所以这些变量没有被立即销毁。
Vue和jquery中使用函数节流去抖
基本的想法是做一个整页滚动的页面
要求是:
1.在鼠标滚轮往下滚动时候不能让函数响应次数过多,而导致页面快速下翻(函数去抖)
2.在鼠标滚轮无限滚动时候,依然能够每个一定时间响应函数(函数节流)
鼠标滚轮事件监听
mounted: function () {
let _this = this
this.globalValues.begin = new Date()
$(document).mousewheel(function (event, delta) {
_this.throttle(_this.mouseRoll, delta, 300, 1300)() //执行throttle函数
})
}
一开始我的trottle函数代码如下
function throttle(method,text,delay,duration){
var timer=null;
var begin=new Date();
return function(){
var context=this
var current=new Date();
clearTimeout(timer);
if(current-begin>=duration){
method.call(context,text);
begin=current;
}else{
timer=setTimeout(function(){
method.call(context,text);
},delay);
}
}
}
发现在闭包在这里面并不适用,原因我认为在于 每次重新执行了throttle这个函数,声明了新的变量timer、begin
_this.throttle(_this.mouseRoll, delta, 300, 1300)() //执行throttle函数
对于这个问题的解决方案,我的想法是在data中定义一个类来装全局的变量,在data中定义的话,这样不会污染整个javascript的全局变量,仅仅是在单个的Vue组件中使用的。
data () {
return {
photoPosition: 0,
globalValues: {
timer: null,
begin: null,
durationNumber: 0,
number: 0
}
}
},
函数去抖和节流的改进
存在一个情况,就是当我快速滑动鼠标滚轮两下的时候,第一下执行函数认为这个是超过duration,所以这一下会立即执行,接下的一下就会执行setTimeout,当我的delay设置的较小的时候,图片给人的感觉是连续向下翻了两张,这个是我所不希望的。
解决的方案:
data中定义一个durationNumber和number
durationNumber:1或是大于1指函数被理解执行过,0指函数没有被理解执行过
number:用来统计函数被立即执行之后鼠标滚轮滚动的次数,这里我希望是鼠标滚轮再滚两次之后再执行setTimout的函数,这样的delay延时给人的感觉要好很多
throttle: function (method, text, delay, duration) {
let _this = this
return function () {
clearTimeout(_this.globalValues.timer)
let current = new Date()
console.log(_this.globalValues.begin)
if (current - _this.globalValues.begin >= duration) {
_this.globalValues.begin = current
_this.globalValues.durationNumber++
method(text)
} else {
if (_this.globalValues.durationNumber) {
_this.globalValues.number++
if (_this.globalValues.number <= 2) {
} else {
_this.globalValues.timer = setTimeout(function () {
method(text)
}, delay)
_this.globalValues.durationNumber = 0
}
}
}
}
}