- 文章看似很长,实则防抖与节流内容类似,理解其一便知其二
- 代码不多,耐心跟着敲一遍,基本能理解防抖和节流思想
防抖节流对比
| 防抖 | 节流 | |
|---|---|---|
| 概念 | 连续的事件,只最后一次触发回调 (如:停止滚动滑动条时,触发一次回调) | 连续的事件,间隔一段时间执行一次回调 (如:滚动滚动条时,每隔一段事件触发一次回调) |
| 应用场景 | 1、避免用户快速点击按钮,持续发送请求 2、搜索框持续输入 3、手机号、邮箱验证 4、鼠标的mousemove、mouseover | 1、滚动加载,加载更多 2、搜索框联想功能 |
防抖
一、原理
事件触发n秒后才能再次发起请求
二、需求场景实例
例:用防抖模拟解决输入框多次发起请求问题
三、实现思路
- 1、实现原始输入
<input type="text"/>
//js
var int = document.querySelector("input");
int.oninput = function(){
console.log(this.value) //模拟业务逻辑
}
- 2、若触发事件,给定一个setTimeOut定时器做延迟触发
- 3、初始化定时器为null
- 4、每次点击,清除且重置定时器
- 5、最后一次点击,即n秒后执行业务逻辑
var int = document.querySelector("input");
var time = null; //初始化定时器
int.oninput = function(){
if(time != null){ //判断是否已存在定时器
clearTimeout(time) //清空定时器
}
time = setTimeout(() => {
console.log(this.value); //模拟业务逻辑
}, 500);
}
效果如下:
四、防抖进阶优化
- 痛点:以上方法将防抖函数和业务逻辑放到一起,代码块不优雅,后期难以维护
- 解决:将防抖函数与业务逻辑单独封装
实现思路
1、封装业务逻辑
//业务逻辑
function task(){
console.log(this.value); //模拟业务逻辑
}
2、封装防抖函数
- 封装一个名为debounce,且返回值为函数的防抖函数,来替代oninput后承接的内容。
- 因为返回值为函数,所以用闭包思想来实现封装
function debounce(){
return function(){}
}
- 防抖函数里传入业务逻辑fn()和延迟时间delay
- 优化全局变量time,把变量time作为私有变量放入debounce函数中
function debounce(fn,delay){
let time = null
return function(){
//此处是防抖逻辑
}
}
3、组装业务逻辑函数和防抖函数(完整代码)
var int = document.querySelector("input");
int.oninput = debounce(task,500)
//业务逻辑
function task(){
console.log(this.value);
}
//防抖函数
function debounce(fn, delay){
var time = null;
return function(){
if(time != null){
clearTimeout(time)
}
time = setTimeout(() => {
fn.call(this) // 注:此处需改变this指针,否则业务逻辑中的this指向window
}, delay);
}
}
节流
一、原理
控制执行次数,n秒内多次触发事件只有1次生效
二、需求场景实例
例:用节流模拟解决滑动浏览器多次请求的问题
三、实现思路
- 1、实现原始输入
<style>
body{
height: 10000px;
}
</style>
//js
window.onscroll = function(){
console.log('触发')
}
2、设置标记变量,限制值为true时,进入计时器计时并执行业务逻辑 3、设置setTimeOut,定时器在规定时间后才能再次触发
var flag = true;
var time = null;
window.onscroll = function(){
if(flag){ //标记变量为true时开始计时
time = setTimeout(() => {
console.log('触发')
flag = true;
}, 500);
}
flag = false; //n秒内flag值为false,不触发计时器
}
效果如下:
四、节流进阶优化
- 痛点:以上方法将节流函数和业务逻辑放到一起,代码块不优雅,后期难以维护
- 解决:将节流函数与业务逻辑单独封装
实现思路
1、封装业务逻辑
function task(){
console.log('触发');
}
2、封装防抖函数
- 封装一个名为throttle,且返回值为函数的节流函数,来替代window.onscroll后承接的内容。
- 因为返回值为函数,所以用闭包思想来实现封装
function throttle(){
return function(){
}
}
- 节流函数里传入业务逻辑fn()和延迟时间delay
- 初始化标记变量flag,值为true
- 优化全局变量flag,time,把变量time作为私有变量放入throttle函数中
function throttle(fn,delay){
var flag = true;
var time = null;
return function(){
}
}
3、组装业务逻辑函数和防抖函数(完整代码)
window.onscroll = throttle(task, 500)
//业务逻辑
function task(){
console.log('触发');
}
//节流函数
function throttle(fn,delay){
var flag = true;
var time = null;
return function(){
if(flag){
time = setTimeout(() => {
fn.call(this)// 注:此处需改变this指针,否则业务逻辑中的this指向window
flag = true;
}, delay)
}
flag = false;
}
}