分金
节流函数,技术上最关键的地方有两点:
1、闭包保存了状态
2、apply的使用
定穴
Debounce
debounce 英[dɪ'baʊns]
美[dɪ'baʊns]
[词典] [计] 防反跳;
口诀:设置一个锁,进门就关闭,干完再打开
的概念其实是从机械开关和继电器的“去弹跳”(debounce)衍生出来的概念。基本思路就是多个信号合并为一个信号。
在JavaScript中,debounce函数所做的事情,就是强制一个函数在某个连续时间段内只执行一次,哪怕它本来会被调用多次。我们希望在用户停止某个操作一段时间之后才执行响应的监听函数,而不是用户操作的过程当中,浏览器出发多少次时间,就执行多少次监听函数。
/***
* 防抖函数
* 每次事件,触发后,过指定时间(time)后执行,如果在在time时间内被触发,
* 会从最近一次次触发的时间,再重新开始执行。
* @param fn
* @param time
*/
function debounce(fn,debounceHold = 200) {
let time = null;
return function () {
let context = this;
let args = arguments;
clearTimeout(time);
time = setTimeout(function () {
// fn.apply(context,args);
fn(args);
},debounceHold);
}
}
export default debounce;
Throttle
throttle 英[ˈθrɒtl]
美[ˈθrɑ:tl]
n. 节流阀; 喉咙,气管; [机] 风门;
vt. 扼杀,压制; 勒死,使窒息; 使节流; (用节汽阀等) 调节;
vi. 节流,减速; 窒息;
看字面意思就能理解大概,就是固定函数执行的速率,即所谓的节流。
正常情况下,mouseOver的监听函数可能会每20ms(假设)执行一次,如果设置200ms的“节流”,那么它就会每200ms执行一次。
/**
* 节流函数
* 控制函数触发的频率
* @param fn
* @param throttlehold
* @returns {Function}
*/
function throttleV1(fn,throttlehold = 200) {
var last;
var time;
return function () {
var context = this;
var args = arguments;
var now = +new Date();
if(last && now < last + throttlehold){
clearTimeout(time);
time = setTimeout(function () {
last = now;
fn.apply(context,args);
},throttlehold);
// 在时间区间的最开始和到达指定间隔的时候执行一次 fn
}else{
last = now;
fn.apply(context,args);
}
}
}
Throttle改进版
相比而言,V2版本思路更加清晰。但是v1是第一次进来后立马执行,v2是只要进来,就会等待一段时间后再执行。所以导致了编程实现的过程完全不同。v1的如果实现v2的功能,就会很麻烦。
var throttleV2 = function(fn, delay, mustRunDelay){
var timer = null;
var t_start;
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);
t_start = t_curr;
}, delay);
}
};
};
在这个拓展后的节流函数升级版,我们可以设置第三个参数,即必然触发执行的时间间隔。如果用下面的方法调用。
window.onresize = throttleV2(myFunc, 50, 100);
则意味着,50ms的间隔内连续触发的调用,后一个调用会把前一个调用的等待处理掉,但每隔100ms至少执行一次。原理也很简单,打时间tag,一开始记录第一次调用的时间戳,然后每次调用函数都去拿最新的时间跟记录时间比,超出给定的时间就执行一次,更新记录时间。