js性能優化:徹底弄懂函數防抖和函數節流

函數防抖和節流

函數防抖和函數節流:優化高頻率執行js代碼的一種手段,js中的一些事件如瀏覽器的resize、scroll,鼠標的mousemove、mouseover,input輸入框的keypress等事件在觸發時,會不斷地調用綁定在事件上的回調函數,極大地浪費資源,降低前端性能。為了優化體驗,需要對這類事件進行調用次數的限制。

函數防抖

在事件被觸發n秒后再執行回調,如果在這n秒內又被觸發,則重新計時。

根據函數防抖思路設計出第一版的最簡單的防抖代碼:

vartimer;// 維護同一個timerfunctiondebounce(fn, delay){clearTimeout(timer);timer = setTimeout(function(){fn();}, delay);}

用onmousemove測試一下防抖函數:

// testfunctiontestDebounce(){console.log('test');}document.onmousemove =()=>{debounce(testDebounce,1000);}

上面例子中的debounce就是防抖函數,在document中鼠標移動的時候,會在onmousemove最后觸發的1s后執行回調函數testDebounce;如果我們一直在瀏覽器中移動鼠標(比如10s),會發現會在10 + 1s后才會執行testDebounce函數(因為clearTimeout(timer)),這個就是函數防抖。

在上面的代碼中,會出現一個問題,var timer只能在setTimeout的父級作用域中,這樣才是同一個timer,并且為了方便防抖函數的調用和回調函數fn的傳參問題,我們應該用閉包來解決這些問題。

優化后的代碼:

functiondebounce(fn, delay){vartimer;// 維護一個 timerreturnfunction(){var_this =this;// 取debounce執行作用域的thisvarargs =arguments;if(timer) {clearTimeout(timer);}timer = setTimeout(function(){fn.apply(_this, args);// 用apply指向調用debounce的對象,相當於_this.fn(args);}, delay);};}

測試用例:

// testfunctiontestDebounce(e, content){console.log(e, content);}vartestDebounceFn = debounce(testDebounce,1000);// 防抖函數document.onmousemove =function(e){testDebounceFn(e,'debounce');// 給防抖函數傳參}

使用閉包后,解決傳參和封裝防抖函數的問題,這樣就可以在其他地方隨便將需要防抖的函數傳入debounce了。

函數節流

每隔一段時間,只執行一次函數。

定時器實現節流函數:

請仔細看清和防抖函數的代碼差異

functionthrottle(fn, delay){vartimer;returnfunction(){var_this =this;varargs =arguments;if(timer) {return;}timer = setTimeout(function(){fn.apply(_this, args);timer =null;// 在delay後執行完fn之後清空timer,此時timer為假,throttle觸發可以進入計時器}, delay)}}

測試用例:

functiontestThrottle(e, content){console.log(e, content);}vartestThrottleFn = throttle(testThrottle,1000);// 節流函數document.onmousemove =function(e){testThrottleFn(e,'throttle');// 給節流函數傳參}

上面例子中,如果我們一直在瀏覽器中移動鼠標(比如10s),則在這10s內會每隔1s執行一次testThrottle,這就是函數節流。

函數節流的目的,是為了限制函數一段時間內只能執行一次。因此,定時器實現節流函數通過使用定時任務,延時方法執行。在延時的時間內,方法若被觸發,則直接退出方法。從而,實現函數一段時間內只執行一次。

根據函數節流的原理,我們也可以不依賴setTimeout實現函數節流。

時間戳實現節流函數:

functionthrottle(fn, delay){varprevious =0;// 使用閉包返回一個函數並且用到閉包函數外面的變量previousreturnfunction(){var_this =this;varargs =arguments;varnow =newDate();if(now - previous > delay) {fn.apply(_this, args);previous = now;}}}// testfunctiontestThrottle(e, content){console.log(e, content);}vartestThrottleFn = throttle(testThrottle,1000);// 節流函數document.onmousemove =function(e){testThrottleFn(e,'throttle');// 給節流函數傳參}

其實現原理,通過比對上一次執行時間與本次執行時間的時間差與間隔時間的大小關系,來判斷是否執行函數。若時間差大于間隔時間,則立刻執行一次函數。并更新上一次執行時間。

異同比較

相同點:

都可以通過使用setTimeout 實現。

目的都是,降低回調執行頻率。節省計算資源。

不同點:

函數防抖,在一段連續操作結束后,處理回調,利用clearTimeout和setTimeout實現。函數節流,在一段連續操作中,每一段時間只執行一次,頻率較高的事件中使用來提高性能。

函數防抖關注一定時間連續觸發的事件只在最后執行一次,而函數節流側重于一段時間內只執行一次。

常見應用場景

函數防抖的應用場景

連續的事件,只需觸發一次回調的場景有:

搜索框搜索輸入。只需用戶最后一次輸入完,再發送請求

手機號、郵箱驗證輸入檢測

窗口大小Resize。只需窗口調整完成后,計算窗口大小。防止重復渲染。

函數節流的應用場景

間隔一段時間執行一次回調的場景有:

滾動加載,加載更多或滾到底部監聽

谷歌搜索框,搜索聯想功能

高頻點擊提交,表單重復提交

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,488評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,034評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,327評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,554評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,337評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,883評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,975評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,114評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,625評論 1 332
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,555評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,737評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,244評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,973評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,615評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,343評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,699評論 2 370

推薦閱讀更多精彩內容