防抖和節(jié)流
為什么需要防抖和節(jié)流
在前端開發(fā)的過程中衡楞,我們經(jīng)常會需要綁定一些持續(xù)觸發(fā)的事件,如 resize敦姻、scroll瘾境、mousemove 等等,但有些時候我們并不希望在事件持續(xù)觸發(fā)的過程中那么頻繁地去執(zhí)行函數(shù)镰惦。
防抖(debounce)
所謂防抖迷守,就是指觸發(fā)事件后在 n 秒內(nèi)函數(shù)只能執(zhí)行一次,如果在 n 秒內(nèi)又觸發(fā)了事件旺入,則會重新計算函數(shù)執(zhí)行時間兑凿。
- 非立即執(zhí)行版
// 非立即執(zhí)行版的意思是觸發(fā)事件后函數(shù)不會立即執(zhí)行,而是在 n 秒后執(zhí)行茵瘾,如果在 n 秒內(nèi)又觸發(fā)了事件礼华,則會重新計算函數(shù)執(zhí)行時間。
function debounce(func, wait) {
let timeout;
return function () {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(context, args)
}, wait);
}
}
// 上述防抖函數(shù)的代碼還需要注意的是 this 和 參數(shù)的傳遞
// 防抖函數(shù)的代碼使用這兩行代碼來獲取 this 和 參數(shù)拗秘,是為了讓 debounce 函數(shù)最終返回的函數(shù) this 指向不變以及依舊能接受到 e 參數(shù)圣絮。
content.onmousemove = debounce(count,1000);
- 立即執(zhí)行版
// 立即執(zhí)行版的意思是觸發(fā)事件后函數(shù)會立即執(zhí)行,然后 n 秒內(nèi)不觸發(fā)事件才能繼續(xù)執(zhí)行函數(shù)的效果雕旨。
function debounce(func,wait) {
let timeout;
return function () {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout);
let callNow = !timeout;
timeout = setTimeout(() => {
timeout = null;
}, wait)
if (callNow) func.apply(context, args)
}
}
- 雙劍合璧版
/**
* @desc 函數(shù)防抖
* @param func 函數(shù)
* @param wait 延遲執(zhí)行毫秒數(shù)
* @param immediate true 表立即執(zhí)行扮匠,false 表非立即執(zhí)行
*/
function debounce(func,wait,immediate) {
let timeout;
return function () {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout);
if (immediate) {
var callNow = !timeout;
timeout = setTimeout(() => {
timeout = null;
}, wait)
if (callNow) func.apply(context, args)
}
else {
timeout = setTimeout(function(){
func.apply(context, args)
}, wait);
}
}
}
節(jié)流
所謂節(jié)流捧请,就是指連續(xù)觸發(fā)事件但是在 n 秒中只執(zhí)行一次函數(shù)。節(jié)流會稀釋函數(shù)的執(zhí)行頻率棒搜。
- 時間戳版
// 在持續(xù)觸發(fā)事件的過程中疹蛉,函數(shù)會立即執(zhí)行,并且每 1s 執(zhí)行一次力麸。
function throttle(func, wait) {
let previous = 0;
return function() {
let now = Date.now();
let context = this;
let args = arguments;
if (now - previous > wait) {
func.apply(context, args);
previous = now;
}
}
}
content.onmousemove = throttle(count,1000);
- 定時器版
// 在持續(xù)觸發(fā)事件的過程中可款,函數(shù)不會立即執(zhí)行,并且每 1s 執(zhí)行一次末盔,在停止觸發(fā)事件后筑舅,函數(shù)還會再執(zhí)行一次
function throttle(func, wait) {
let timeout;
return function() {
let context = this;
let args = arguments;
if (!timeout) {
timeout = setTimeout(() => {
timeout = null;
func.apply(context, args)
}, wait)
}
}
}
我們應(yīng)該可以很容易的發(fā)現(xiàn)座慰,其實時間戳版和定時器版的節(jié)流函數(shù)的區(qū)別就是陨舱,時間戳版的函數(shù)觸發(fā)是在時間段內(nèi)開始的時候,而定時器版的函數(shù)觸發(fā)是在時間段內(nèi)結(jié)束的時候版仔。
- 雙劍合璧版
/**
* @desc 函數(shù)節(jié)流
* @param func 函數(shù)
* @param wait 延遲執(zhí)行毫秒數(shù)
* @param type 1 表時間戳版游盲,2 表定時器版
*/
function throttle(func, wait ,type) {
if(type===1){
let previous = 0;
}else if(type===2){
let timeout;
}
return function() {
let context = this;
let args = arguments;
if(type===1){
let now = Date.now();
if (now - previous > wait) {
func.apply(context, args);
previous = now;
}
}else if(type===2){
if (!timeout) {
timeout = setTimeout(() => {
timeout = null;
func.apply(context, args)
}, wait)
}
}
}
}