Published
Edited
Sep 1, 2021
Insert cell
md`# 防抖与节流`
Insert cell
md`## 防抖(debounce)`
Insert cell
md`简单实现:每次直接清除掉之前的定时器任务,重新设置新的定时器任务`
Insert cell
debounce = (func,wait)=>{
// 定时器
let timer = null;
// 返回一个函数 要接收函数的参数
return function(){
const context = this;
const args = arguments;
clearTimeout(timer);
timer = setTimeout(function(){
func.apply(context,args);
}, wait);
}
}
Insert cell
html`<input type="text" id="input"/><span id="content"></span>`
Insert cell
// 测试
{
const el = document.getElementById('input');
const handler = (e)=>{
const {value} = e.target;
// 打开控制台查看效果
console.log('input value----->',value);
}
const debounceHandler = debounce(handler,500);
document.addEventListener('keyup',debounceHandler);
}
Insert cell
md`underscore实现debounce`
Insert cell
_now = ()=>new Date().getTime();
Insert cell
/**
* 空闲控制 返回函数连续调用时,空闲时间必须大于或等于 wait,func 才会执行
* @param {function} func 传入函数
* @param {number} wait 表示时间窗口的间隔
* @param {boolean} immediate 配置回调函数是在一个时间区间的最开始执行(true),还是最后执行(false)
* @return {function} 返回调用函数
*/
_debounce = function(func, wait, immediate) {
var timeout, args, context, timestamp, result;
var later = function() {
var last = _now() - timestamp;
if (last < wait && last > 0) {
timeout = setTimeout(later, wait - last);
} else {
timeout = null;
if (!immediate) {
result = func.apply(context, args);
if (!timeout) context = args = null;
}
}
};

return function() {
context = this;
args = arguments;
timestamp = _now();
var callNow = immediate && !timeout;
if (!timeout) timeout = setTimeout(later, wait);
if (callNow) {
result = func.apply(context, args);
context = args = null;
}

return result;
};
};
Insert cell
md`## 节流(throttle)`
Insert cell
md`简单实现:如果和上次出发时间相比超出了设置的等待时间就执行函数;否则重新设置设置定时器时间并返回定时器`
Insert cell
throttle = (func,wait=160)=>{
let timestamp;
let timer;
return function(){
const context = this;
const args = arguments;
const now = _now();
const remaining = wait - (now - timestamp);
if(timestamp && remaining > 0){
clearTimeout(timer);
//让方法在脱离事件后也能执行一次
timer = setTimeout(()=>{
func.apply(context,args);
},remaining);
}else{
// 在时间区间的最开始和到达指定间隔的时候执行一次
timestamp = now
func.apply(context, args)
}
}
}
Insert cell
html`<div id="block" style="width:150px;height:150px;border:1px solid red;overflow:auto"><div id="child" style="height:1500px;background:#eee">xxx</div></div>`
Insert cell
{
const el = document.getElementById('block');
const handler = (e)=>{
console.log('scroll-->');
}
const throttleHandler = throttle(handler,500);
el.addEventListener('scroll',throttleHandler);
}
Insert cell
md`underscore实现`
Insert cell
_throttle = function(func, wait, options) {
var context, args, result;
var timeout = null;
var previous = 0;
if (!options) options = {};
var later = function() {
previous = options.leading === false ? 0 : _now();
timeout = null;
result = func.apply(context, args);
if (!timeout) context = args = null;
};
return function() {
var now = _now();
if (!previous && options.leading === false) previous = now;
var remaining = wait - (now - previous);
context = this;
args = arguments;
if (remaining <= 0 || remaining > wait) {
clearTimeout(timeout);
timeout = null;
previous = now;
result = func.apply(context, args);
if (!timeout) context = args = null;
} else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining);
}
return result;
};
};
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more