javascript函數(shù)的節(jié)流[throttle]與防抖[debounce]
防抖和節(jié)流
窗口的resize、scroll,輸入框內(nèi)容校驗(yàn)等操作時(shí),如果這些操作處理函數(shù)較為復(fù)雜或頁(yè)面頻繁重渲染等操作時(shí),如果事件觸發(fā)的頻率無(wú)限制,會(huì)加重瀏覽器的負(fù)擔(dān),導(dǎo)致用戶體驗(yàn)非常糟糕。此時(shí)我們可以采用debounce(防抖)和throttle(節(jié)流)的方式來(lái)減少觸發(fā)的頻率,同時(shí)又不影響實(shí)際效果。
這兩個(gè)東西都是為了項(xiàng)目?jī)?yōu)化而出現(xiàn)的,官方是沒(méi)有具體定義的,他們的出現(xiàn)主要是為了解決一些短時(shí)間內(nèi)連續(xù)執(zhí)行的事件帶來(lái)性能上的不佳和內(nèi)存的消耗巨大等問(wèn)題;
像這類事件一般像 scroll keyup mousemove resize等等,短時(shí)間內(nèi)不斷的觸發(fā),在性能上消耗是非常大的,尤其是一些改變DOM結(jié)構(gòu)的操作;
節(jié)流[throttle]與防抖[debounce]非常相似,都是讓上述這類事件在規(guī)定的事件從不斷的去觸發(fā)更改成為規(guī)定的時(shí)間內(nèi)觸發(fā)多少次;
節(jié)流[throttle]
節(jié)流通俗來(lái)解釋就比如我們水龍頭放水,閥門一打開,水嘩嘩的往下流,這個(gè)秉著勤儉節(jié)約的優(yōu)良傳統(tǒng)美德,我們要把水龍頭關(guān)小點(diǎn),最好是如我們心意按照一定規(guī)律在某個(gè)時(shí)間間隔內(nèi)一滴一滴的往下滴,這,,,好吧這就是我們節(jié)流的概念;
換成函數(shù)來(lái)說(shuō),使用setTimeout方法,給定兩個(gè)時(shí)間,后面的時(shí)間減去前面的時(shí)間,到達(dá)我們給定的時(shí)間就去觸發(fā)一次這個(gè)事件,這么說(shuō)太籠統(tǒng)的,我們看下面的函數(shù),這里我們以【scroll】為例;
/** 樣式我就順便寫了 **/
<style>
*{padding:0;margin:0;}
.scroll-box{
width : 100%;
height : 500px;
background:blue;
overflow : auto;
}
.scroll-item{
height:1000px;
width:100%;
}
</style>
------------------------
/** 先給定DOM結(jié)構(gòu);**/ <div class="scroll-box"> <div class="scroll-item"></div> </div>
------------------------
/**主要看js,為了簡(jiǎn)單我用JQ去寫了**/
<script>
$(document).ready(function(){
var scrollBox = $('.scroll-box');
//調(diào)用throttle函數(shù),傳入相應(yīng)的方法和規(guī)定的時(shí)間;
var thro = throttle(throFun,300);
//觸發(fā)事件;
scrollBox.on('scroll' , function(){
//調(diào)用執(zhí)行函數(shù);
thro();
})
// 封裝函數(shù);
function throttle(method,time){
var timer = null;
var startTime = new Date();
return function(){
var context = this;
var endTime = new Date();
var resTime = endTime - startTime;
//判斷大于等于我們給的時(shí)間采取執(zhí)行函數(shù);
if(resTime >= time){
method.call(context);
//執(zhí)行完函數(shù)之后重置初始時(shí)間,等于最后一次觸發(fā)的時(shí)間
startTime = endTime;
}
}
}
function throFun(){
console.log('success');
}
})
</script>
通過(guò)以上的函數(shù),我們就可以做到節(jié)流的效果,在規(guī)定的每300毫秒觸發(fā)一次,當(dāng)然時(shí)間可以自定義,根據(jù)需求來(lái);
防抖[debounce ]
寫代碼之前,我們先清楚一下防抖的概念,不知道大家有沒(méi)有做過(guò)電腦端兩邊懸浮廣告窗口的這么一個(gè)東西,當(dāng)我們拖動(dòng)滾動(dòng)條的時(shí)候,兩邊的廣告窗口會(huì)因?yàn)闈L動(dòng)條的拖動(dòng),而不斷的嘗試著去居于中間,然后你就會(huì)看到這兩個(gè)窗口,不停的抖啊抖;
一般這種就叫抖動(dòng)了,我們要做的就是防止這種抖動(dòng),稱為防抖[debounce ];
那這里防抖思想就是當(dāng)我們拖動(dòng)完成之后,兩邊的窗口位置再重新去計(jì)算,這樣,就會(huì)顯得很平滑,看著很舒服了,最主要的操作DOM結(jié)構(gòu)的次數(shù)就大大減少了;
優(yōu)化了頁(yè)面性能,降低了內(nèi)存消耗,不然你像IE這種比較老點(diǎn)版本的瀏覽器,說(shuō)不定就直接給你蹦了
用書面一點(diǎn)的說(shuō)法就是,在某個(gè)事件沒(méi)有結(jié)束之前,函數(shù)不會(huì)執(zhí)行,當(dāng)結(jié)束之后,我們給定延時(shí)時(shí)間,然他在給定的延時(shí)時(shí)間之后再去執(zhí)行這個(gè)函數(shù),這就是防抖函數(shù);
來(lái)看代碼:
//將上面的throttle函數(shù)替換為debounce函數(shù);
function debounce(method,time){
var timer = null ;
return function(){
var context = this;
//在函數(shù)執(zhí)行的時(shí)候先清除timer定時(shí)器;
clearTimeout(timer);
timer = setTimeout(function(){
method.call(context);
},time);
}
}
思路就是在函數(shù)執(zhí)行之前,我們先清除定時(shí)器,如果函數(shù)一直執(zhí)行,就會(huì)不斷的去清除定時(shí)器中的方法,知道我們操作結(jié)束之后,函數(shù)才會(huì)執(zhí)行;
其實(shí)書寫的方式有很多,主要還是思路的問(wèn)題,大家寫的多了,自然就知道了;
用途
- 當(dāng)我們做keyup像后臺(tái)請(qǐng)求檢驗(yàn)的時(shí)候,可以使用防抖函數(shù),不然我們每按一次鍵盤就請(qǐng)求一次,請(qǐng)求太頻繁,這樣當(dāng)我們結(jié)束按鍵盤的時(shí)候再去請(qǐng)求,請(qǐng)求少很多了,性能自然不用說(shuō);
- resize 窗口大小調(diào)整的時(shí)候,我們可以采用防抖技術(shù)也可以使用節(jié)流;
- mousemove 鼠標(biāo)移動(dòng)事件我們既可以采用防抖也可以使用節(jié)流;
- scroll 滾動(dòng)條觸發(fā)的事件,當(dāng)然既可以采用防抖也可以采用節(jié)流;
- 連續(xù)高頻發(fā)的事件都可以采用這兩種方式去解決,優(yōu)化頁(yè)面性能;
具體的采用哪一種更較為合適,主要還是看你的業(yè)務(wù)需求,好了,本篇就到這里了,感謝大家閱讀;希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
JavaScript模板引擎應(yīng)用場(chǎng)景及實(shí)現(xiàn)原理詳解
這篇文章主要介紹了JavaScript模板引擎應(yīng)用場(chǎng)景及實(shí)現(xiàn)原理,結(jié)合實(shí)例形式詳細(xì)分析了javascript模版引擎的具體應(yīng)用場(chǎng)景、實(shí)現(xiàn)原理、相關(guān)操作技巧與注意事項(xiàng),需要的朋友可以參考下2018-12-12
js實(shí)現(xiàn)視頻鏡面反轉(zhuǎn)的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用JavaScript實(shí)現(xiàn)視頻鏡面反轉(zhuǎn)的效果,文中的示例代碼簡(jiǎn)潔易懂,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-11-11
Textbox控件注冊(cè)回車事件及觸發(fā)按鈕提交事件具體實(shí)現(xiàn)
Lyncplus客戶端中訪問(wèn)Web頁(yè)面時(shí)遇到了TextBox控件回車自動(dòng)完成按鈕的提交事件失效的情況,于是上網(wǎng)查找相關(guān)的介紹最終解決了這兩個(gè)問(wèn)題,感興趣的你可以參考下或許對(duì)你有所幫助2013-03-03
詳解javascript傳統(tǒng)方法實(shí)現(xiàn)異步校驗(yàn)
這篇文章主要為大家介紹了javascript實(shí)現(xiàn)異步校驗(yàn)的方法,感興趣的小伙伴們可以參考一下2016-01-01
js前端實(shí)現(xiàn)登錄拼圖驗(yàn)證功能
行為驗(yàn)證碼通過(guò)用戶的操作來(lái)完成驗(yàn)證,常見的行為驗(yàn)證碼有拖動(dòng)式和點(diǎn)觸式,下面這篇文章主要給大家介紹了關(guān)于js前端實(shí)現(xiàn)登錄拼圖驗(yàn)證功能的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-02-02
快速掌握WordPress中加載JavaScript腳本的方法
這篇文章主要介紹了快速掌握WordPress中加載JavaScript腳本的方法,以及響應(yīng)的CSS樣式加載方法的簡(jiǎn)介,需要的朋友可以參考下2015-12-12
實(shí)現(xiàn)兩個(gè)文本框同時(shí)輸入的實(shí)例
下面小編就為大家?guī)?lái)一篇實(shí)現(xiàn)兩個(gè)文本框同時(shí)輸入的實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-09-09
JavaScript正則表達(dá)式小結(jié)(test|match|search|replace|split|exec)
這篇文章主要介紹了JavaScript正則表達(dá)式小結(jié)(test|match|search|replace|split|exec)的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下吧2016-12-12
原生JS實(shí)現(xiàn)勻速圖片輪播動(dòng)畫
這篇文章主要為大家詳細(xì)介紹了原生JS實(shí)現(xiàn)勻速圖片輪播動(dòng)畫,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-10-10

