防抖函数(debounce)
短时间内多次触发同一事件,只执行最后一次,或者只执行最开始的一次,中间的不执行。
应用场景:
- search搜索联想,用户在不断输入值时,用防抖来节约请求资源。
- window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次
分类:
- 立即执行版
立即执行版的意思是触发事件后函数会立即执行,然后 n 秒内不触发事件才能继续执行函数的效果。
function debounce(fn,wait = 500){
let timer = null;
let arg = arguments;
let flag = true;
return function(){
clearTimeout(timer);
if(flag){
fn.apply(this,arg)
flag = false
}
timer = setTimeout(()=>flag = true,wait)
}
}
function spake(){
console.log('防抖成功')
}
window.onmousemove = debounce(spake,3000)
- 非立即执行版
非立即执行版的意思是触发事件后函数不会立即执行,而是在 n 秒后执行,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
// 非立即执行版
function debounce(fn,wait = 500){
let timer = null;
let arg = arguments;
return function(){
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this,arg)
}, wait);
}
}
function spake(){
console.log('防抖成功')
}
let a = document.getElementById('a');
a.addEventListener('input',debounce(spake,1000))
整合版
/*
* @param fn 目标函数
* @param wait 延迟执行毫秒数
* @param isImmediate true-立即执行;false-非立即执行
*/
function debounce(fn, wait, isImmediate = false) {
let timer = null;
let arg = arguments;
let flag = true;
if (isImmediate) {
return function () {
clearTimeout(timer);
if (flag) {
fn.apply(this, arg)
flag = false
}
timer = setTimeout(() => flag = true, wait)
}
}
return function(){
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this,arg)
}, wait);
}
}
function spake() {
console.log('防抖成功')
}
window.onmousemove = debounce(spake, 1000,true)
节流(throttle)
一个时间在n秒钟被多次触发,但是绑定的函数在期间只会执行一次(及稀释函数的执行频率)
应用场景:
- 鼠标不断点击触发,mousedown(单位时间内只触发一次)
- 监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断
分类:
- 时间戳版
在持续触发事件的过程中,函数会立即执行,并且每 1s 执行一次。
function throttle(fn, wait = 500) {
let timer = 0;
return function () {
let arg = arguments;
let now = Date.now();
if (now - timer >= wait) {
fn.apply(this,arg)
timer = now
}
}
}
function spake() {
console.log('节流成功')
}
window.onmousemove = throttle(spake,1000)
- 定时器版
在持续触发事件的过程中,函数不会立即执行,并且每 1s 执行一次,在停止触发事件后,函数还会再执行一次。
function throttle(fn,wait=500){
let timer;
return function(){
let arg = arguments;
if(!timer){
timer = setTimeout(()=>{
timer = null;
fn.apply(this,arg)
},wait)
}
}
}
function spake() {
console.log('节流成功')
}
window.onmousemove = throttle(spake,1000)
两者区别在于时间戳版的在时间段开始时触发,而定时器版在时间段结束时触发
整合版
/*
* @param fn 函数
* @param wait 延迟执行毫秒数
* @param type 1-时间戳版,2-定时器版 默认为1
*/
function throttle(fn,wait=500,type=1){
if(type === 1){
var pre = 0;
}else if(type === 2){
var timer;
}
return function(){
let arg = arguments;
if(type === 1){
let now = Date.now();
if(now - pre >= wait){
fn.apply(this,arg);
pre = now;
}
}
else if(type === 2){
if(!timer){
timer = setTimeout(()=>{
timer = null;
fn.apply(this,arg)
},wait)
}
}
}
}
function spake() {
console.log('节流成功')
}
window.onmousemove = throttle(spake,1000,2)