lodash 提供了throttle节流API、debounce 防抖API
理解源码前,回顾JavaScript闭包原理:
let a = 1;
function f(){
let a = 0;
return function (b) {
console.log(a,b);
return a++ + b++;
}
}
const res = f();
console.log(res(a)); // 0+1
console.log(res(a)); // 1+1
console.log(res(a)); // 2+1
const res1 = f();
console.log(res1(a)); // 0+1
console.log(res1(a)); // 1+1
console.log(res1(a)); // 2+1
函数防抖
多次接近的(相隔不超过时间设置)操作合并为一次操作进行,只在最后一次事件触发一次函数;或者第一次触发,下一次调用必须与前一次调用的时间间隔大于wait才会触发
适用于
- 搜索问题,希望用户输入完最后一个字才调用查询接口
- 用户点star的时候,希望用户点第一下的时候就去调用接口,且成功之后改变star按钮的样子
实现:维护一个定时器,返回一个推迟执行的函数
//防抖debounce
function debounce(fn) {
let timer = null; //闭包:维护一个计时器,创建一个标记存放定时器的返回值
return function () {
// 规定在delay时间后触发函数,但是在delay时间内再次触发的话,就会取消之前的计时器而重新设置。
clearTimeout(timer);
// 然后又创建一个新定时
timer = setTimeout(() => {
fn.apply(this, arguments);
}, 500000000);
};
}
// 处理函数
function handle() {
console.log("处理中");
}
// 滚动事件
window.addEventListener('scroll', debounce(handle));
立即执行版本:
function getFixedLength(pre, len){
let tempArray = pre.toString().split('');
let addLen = len - tempArray.length;
while(addLen--){
tempArray.unshift(0);
}
return tempArray.join('');
}
// 用来获取当前时间戳的
function getCurrentTime() {
const now = new Date();
const min = getFixedLength(now.getMinutes(), 2);
const sec = getFixedLength(now.getMilliseconds(), 3);
const timeString = min + sec;
return Number(timeString);
}
function debounce(fn, wait = 50) {
let start = null; //闭包:维护一个计时器,创建一个标记存放定时器的返回
let now = null;
return function () {
const now = getCurrentTime();
const isTime = start ? (now - start >= wait? true : false): true;
if(isTime){
fn();
start = getCurrentTime();
}
console.log('now',now,'start',start,'is',isTime);
};
}
// 处理函数
function handle() {
console.log("pop");
}
// 滚动事件
window.addEventListener('scroll', debounce(handle, 500));
函数节流
规定时间内只触发一次函数。原理是通过判断是否有延迟调用函数未执行
页面的无限加载场景下,我们需要用户在滚动页面时,每隔一段时间发一次 Ajax 请求,而不是在用户停下滚动页面操作时才去请求数据。适合用节流技术来实现。
//节流throttle
function throttle(fn) {
let isDoing= false; // 通过闭包保存一个标记
return function () {
// 在函数开头判断标记是否为true,不为true则return
if (isDoing) return;
// 设置为false,维护的时间起点
isDoing = true;
setTimeout(() => {
fn.apply(this, arguments);
isDoing= false;//执行完毕,时间终点
}, 1000);
};
}
function http(e) {
//
}
window.addEventListener('resize', throttle(http));
requestAnimationFrame浏览器原理节流
requestAnimationFrame使用一个回调函数作为参数。这个回调函数会在浏览器重绘之前调用。
window.addEventListener('scroll', () =>{
window.requestAnimationFrame(handle);
}
);
无限滚动:滚动+分页器
思考:向上翻看消息记录怎么实现?
局部加载DOM