在前端開發(fā)的過程中纪他,我們經(jīng)常會需要綁定一些持續(xù)觸發(fā)的事件,如resize晾匠、scroll止喷、mousemove等等,但有些時候我們并不希望在事件持續(xù)觸發(fā)的過程中那么頻繁地去執(zhí)行函數(shù)混聊。
var son=document.getElementById("son")
son.onmousedown = debounce (count, wait)
無論防抖還是節(jié)流弹谁,都要知道debounce是返回一個function乾巧,所以每次點擊執(zhí)行的是return里面的函數(shù)。所以timeout不會被重新聲明预愤。
因此執(zhí)行到里面的function沟于,調(diào)用時寫debounce()()
1.防抖
- 思路:
每次觸發(fā)事件時都取消之前的延時調(diào)用方法。
(1)立即執(zhí)行版本
設(shè)定時間過了以后植康,timeout=null旷太,callNow不為空,就可以執(zhí)行新的操作了销睁。如果還在設(shè)定時間之內(nèi)供璧,不會觸發(fā)處理函數(shù)。幾秒之后冻记,這個timeout=null睡毒,可以重新觸發(fā)處理函數(shù)了
function debounce2 (func, wait){ //防抖函數(shù)(立即執(zhí)行)
let timeout;
return function(){
if(timeout) {
console.log("清理定時器")
clearTimeout(timeout)
}
let callNow =!timeout
timeout =setTimeout(()=>{
timeout=null
},wait)
if(callNow) {
func.apply(this)
}
}
}
(2)非立即執(zhí)行版本
觸發(fā)高頻事件后n秒內(nèi)函數(shù)只會執(zhí)行一次,如果n秒內(nèi)高頻事件再次被觸發(fā)冗栗,則清掉原來的計時器演顾,之前的計時器還沒執(zhí)行就被刪掉,永遠不會執(zhí)行了
function debounce (func, wait){ //防抖函數(shù)(非立即執(zhí)行)隅居,一段時間內(nèi)多次操作化為一次钠至,
let timeout;
return function(){
let context = this;
if(timeout) {
clearTimeout(timeout)
}
timeout=setTimeout(()=>{
func.apply(this)
},wait)
}
}
防抖技術(shù)僅靠傳入延遲時間值的大小控制高頻事件的觸發(fā)頻率,如果傳入的延遲時間值比較大胎源,那么就會出現(xiàn)一定的問題棉钧。例如當傳入延遲時間為1000ms,那么當用戶滾動速度大于1000ms/次時涕蚤,則無論鼠標滾動多久都不會觸發(fā)事件處理函數(shù)掰盘。因此防抖技術(shù)存在一定的缺陷,會不適用于某些場景赞季,例如圖片懶加載愧捕。這個時候節(jié)流就派上用場了。
2.節(jié)流
高頻事件觸發(fā)申钩,但在n秒內(nèi)只會執(zhí)行一次次绘,所以節(jié)流會稀釋函數(shù)的執(zhí)行頻率
- 思路:
每次觸發(fā)事件時都判斷當前是否有等待執(zhí)行的延時函數(shù)
(1)時間戳版本
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;
}
}
}
函數(shù)會立即執(zhí)行
(2)定時器版本
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)
}
}
}