搞懂debounce(防抖)和throttle(節(jié)流)

這篇文章講概念帖旨、應(yīng)用場景和實現(xiàn)思路,源碼在最后面彬呻。

性能和速度是程序的敵人衣陶,以致于每一個優(yōu)秀的程序員都在孜孜不倦的提升軟件的性能和速度,從而提升產(chǎn)品的用戶體驗闸氮。

下面介紹的是debounce和throttle剪况,這兩種技術(shù)能夠改善程序的性能,它們非常相似但是不同的技術(shù)蒲跨。

當(dāng)dom事件被頻繁觸發(fā)時译断,使用debounce或throttle就非常有用了,因為它能夠在事件和函數(shù)執(zhí)行之間添加一層控制或悲。

這里推薦使用Lodash工具庫孙咪,引入后直接使用_.debounce_.throttle,非常簡單和方便,當(dāng)然前提是需要理解它們的作用巡语。

debounce防抖動

debounce允許我們把一組調(diào)用壓縮為單個調(diào)用翎蹈。

想象一下你在電梯里面,門準(zhǔn)備關(guān)上男公,突然荤堪,有人闖進(jìn)來,這時電梯不會開始移動枢赔,而是門重新打開澄阳,然后等待一會。如果還有人進(jìn)來踏拜,它會重復(fù)這一過程碎赢,直到?jīng)]有人再進(jìn)來,最后門自動關(guān)上速梗,電梯開始在樓層間移動肮塞。這是為什么?因為工程師們也對電梯進(jìn)行了資源優(yōu)化镀琉,用更少的資源完成任務(wù)峦嗤,充分發(fā)揮電梯的效用。這個電梯的例子跟debounce的應(yīng)用場景非常相似屋摔。

應(yīng)用場景:

  1. 調(diào)整resize烁设。
    當(dāng)監(jiān)聽了窗口的resize事件時,并且調(diào)整瀏覽器窗口大小的時候,會觸發(fā)大量的resize事件装黑,所以呢當(dāng)你拖拽的時候副瀑,調(diào)用處理函數(shù)做大量計算的時候,會發(fā)現(xiàn)拖拽的過程有點卡頓恋谭,掉幀糠睡。

這時我們可以使用debounce,因為我們關(guān)注的是最終值疚颊,也就是我們最后停止拖動瀏覽器窗口的值狈孔。

  1. input的輸入和發(fā)送請求。
    在input里輸入文字然后發(fā)送網(wǎng)絡(luò)請求材义,有一種較優(yōu)的方案就是期望用戶輸入完畢然后再發(fā)送網(wǎng)絡(luò)請求均抽,而不是輸入的過程中不斷的發(fā)出請求,這能有效的優(yōu)化網(wǎng)絡(luò)服務(wù)其掂。

throttle節(jié)流

throttle 只允許在每x毫秒內(nèi)執(zhí)行一次操作油挥。

它跟debounce的不同主要是:throttle的執(zhí)行是有規(guī)律的,會每x毫秒內(nèi)執(zhí)行一次款熬。

使用場景:
一個相當(dāng)普遍的例子深寥,用戶在使用一個無限滾動的頁面,你需要檢測用戶的位置到底部之間的距離贤牛,如果用戶接近屏幕底部惋鹅,我們應(yīng)該發(fā)送Ajax請求更多內(nèi)容然后添加到頁面上。實現(xiàn)這一功能需要監(jiān)聽頁面的scroll事件盔夜,然而在手機(jī)端緩慢的滾動頁面會觸發(fā)上百次事件负饲,這時候有了throttle就可以對其進(jìn)行優(yōu)化,比如每250ms內(nèi)只調(diào)用一次喂链,這樣用戶基本感覺不到有任何體驗上的差別,也優(yōu)化了程序的性能妥泉。

在這里我們心愛的debounce是不適合的椭微,因為debounce只在用戶停止?jié)L動時才觸發(fā)(調(diào)用)函數(shù)。而我們需要的是在用戶在滾動頁面過程中快要到達(dá)底部的時候獲取更多內(nèi)容盲链,使用throttle才能持續(xù)的進(jìn)行檢測用戶位置到底部之間的距離蝇率。

requestAnimationFrame (rAF)

rAF 是對函數(shù)的執(zhí)行進(jìn)行限速的額外的一種方式。大致等同于_.throttle(dosomething, 16)刽沾。但它可以是throttle的替代者本慕,它更流暢和平滑,它是瀏覽器的標(biāo)準(zhǔn)API侧漓。

根據(jù)經(jīng)驗锅尘,我使用rAF函數(shù)的一些場景主要是繪畫或動畫,重新計算元素的位置等布蔗。

觸發(fā)網(wǎng)絡(luò)請求或決定是否添加/移除一個class(觸發(fā)一個CSS動畫)藤违,我會考慮_.debounce or _.throttle浪腐,使用它們你能更靈活的控制執(zhí)行速率(用200ms替換16ms)。

在underscore或lodash這兩個框架里面都沒有提供或?qū)崿F(xiàn)rAF顿乒,因為使用它非常的簡單议街。

例子:

var start = null;
var element = document.getElementById('SomeElementYouWantToAnimate');
element.style.position = 'absolute';

function step(timestamp) {
  if (!start) start = timestamp;
  var progress = timestamp - start;
  element.style.left = Math.min(progress / 10, 200) + 'px';
  if (progress < 2000) {
    window.requestAnimationFrame(step);
  }
}

window.requestAnimationFrame(step);

總結(jié):
使用debounce, throttle and requestAnimationFrame來優(yōu)化你的事件操作。三者的技術(shù)和思路都略微不同璧榄,但它們都是非常有用以及彼此互補特漩。

  • debounce:debounce允許我們把一組事件調(diào)用壓縮為單個調(diào)用。
  • throttle:每x毫秒執(zhí)行一次骨杂。就像每隔200毫秒檢查一次滾動位置涂身。
  • requestAnimationFrame:可以是throttle的替代者,當(dāng)你的函數(shù)為重新計算和渲染元素到屏幕上腊脱,而且你想得到平滑的過渡動畫访得。注意:不支持IE9。

Github:
throttle 和 debounce函數(shù)代碼

實現(xiàn)思路:

  • debounce:創(chuàng)建一個指定x毫秒的setTimeout(fn,x)陕凹,如果在該setTimeout(fn,x)的x毫秒內(nèi)再次產(chǎn)生新的事件悍抑,就會先去取消該setTimeout,然后重新創(chuàng)建一個指定x毫秒的setTimeout(fn,x)杜耙,不斷重復(fù)這一過程搜骡,直到?jīng)]有再產(chǎn)生新的事件,x毫秒后調(diào)用函數(shù)fn佑女。
  • throttle:setTimeout(fn,x - elapsed)记靡。節(jié)流的實現(xiàn)要多兩個額外的變量,一個是記錄上一次函數(shù)fn執(zhí)行的時間(lastExec)团驱,一個是記錄流逝的時間(elapsed) = 當(dāng)前setTimeout創(chuàng)建的時間 - 上一次函數(shù)fn執(zhí)行的時間(lastExec)摸吠,每產(chǎn)生一個新的事件(創(chuàng)建新的setTimeout),都會先去取消上一個setTimeout,所以它的定時器要這么寫setTimeout(fn,x - elapsed)就能每x毫秒執(zhí)行一次函數(shù)fn了嚎花,每一次函數(shù)fn被執(zhí)行都會更新lastExec的值為當(dāng)前時間寸痢。

參考資料:
https://css-tricks.com/debouncing-throttling-explained-examples/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市紊选,隨后出現(xiàn)的幾起案子啼止,更是在濱河造成了極大的恐慌,老刑警劉巖兵罢,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件献烦,死亡現(xiàn)場離奇詭異,居然都是意外死亡卖词,警方通過查閱死者的電腦和手機(jī)巩那,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人拢操,你說我怎么就攤上這事锦亦。” “怎么了令境?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵杠园,是天一觀的道長。 經(jīng)常有香客問我舔庶,道長抛蚁,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任惕橙,我火速辦了婚禮瞧甩,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘弥鹦。我一直安慰自己肚逸,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布彬坏。 她就那樣靜靜地躺著朦促,像睡著了一般。 火紅的嫁衣襯著肌膚如雪栓始。 梳的紋絲不亂的頭發(fā)上务冕,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天,我揣著相機(jī)與錄音幻赚,去河邊找鬼禀忆。 笑死,一個胖子當(dāng)著我的面吹牛落恼,可吹牛的內(nèi)容都是我干的箩退。 我是一名探鬼主播,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼佳谦,長吁一口氣:“原來是場噩夢啊……” “哼乏德!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起吠昭,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎胧瓜,沒想到半個月后矢棚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡府喳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年蒲肋,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡兜粘,死狀恐怖申窘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情孔轴,我是刑警寧澤剃法,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站路鹰,受9級特大地震影響贷洲,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜晋柱,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一优构、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧雁竞,春花似錦钦椭、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至联贩,卻和暖如春漫仆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背泪幌。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工盲厌, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人祸泪。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓吗浩,卻偏偏與公主長得像,于是被迫代替她去往敵國和親没隘。 傳聞我的和親對象是個殘疾皇子懂扼,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,976評論 2 355