【前言】
在工作中,我們可能碰到這樣的問題:
- 用戶在搜索的時候,在不停敲字,如果每敲一個字我們就要調一次接口,接口調用太頻繁,給卡住了。
- 用戶在閱讀文章的時候,我們需要監聽用戶滾動到了哪個標題,但是每滾動一下就監聽,那樣會太過頻繁從而占內存,如果再加上其他的業務代碼,就卡住了。
所以,這時候,我們就要用到 防抖與節流 了。
那么,講到 防抖與節流,我們可以順帶探秘下 重繪與回流。
說起 重繪與回流,我們就順帶把 瀏覽器輸入 URL 后發生的事情 也關注一下,從而引出 DNS、TCP 等知識點,最終串起來構成本文的輪廓,方便 jsliang 和小伙伴們對這塊知識的整理與記憶。
【主體】
本節主要介紹函數防抖debounce
下面我們有段防抖小案例代碼。
如果小伙伴們手頭有電腦,並感興趣想先自己思考下什么是防抖。可以將代碼復制到瀏覽器,嘗試點擊按鈕,並關注下控制台,看看 Console 是如何打印的。
如果小伙伴們手頭沒有電腦,那么咱一起先瞅瞅代碼實現,再看看下面 GIF 演示。(這樣效果沒有自己敲的直白有效)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>防抖</title> </head> <body> <button id="debounce">點我防抖!</button> <script> window.onload = function() { // 1、獲取這個按鈕,並綁定事件 var myDebounce = document.getElementById("debounce"); myDebounce.addEventListener("click", debounce(sayDebounce)); } // 2、防抖功能函數,接受傳參 function debounce(fn) { // 4、創建一個標記用來存放定時器的返回值 let timeout = null; return function() { // 5、每次當用戶點擊/輸入的時候,把前一個定時器清除 clearTimeout(timeout); // 6、然后創建一個新的 setTimeout, // 這樣就能保證點擊按鈕后的 interval 間隔內 // 如果用戶還點擊了的話,就不會執行 fn 函數 timeout = setTimeout(() => { fn.call(this, arguments); }, 1000); }; } // 3、需要進行防抖的事件處理 function sayDebounce() { // ... 有些需要防抖的工作,在這里執行 console.log("防抖成功!"); } </script> </body> </html>
很好,相信小伙伴們已經看完了代碼,下面我們看看它的演示:
這時候,我們可以拋出防抖的概念了:
- 防抖:任務頻繁觸發的情況下,只有任務觸發的間隔超過指定間隔的時候,任務才會執行。
結合上面的代碼,我們可以了解到,在觸發點擊事件后,如果用戶再次點擊了,我們會清空之前的定時器,重新生成一個定時器。意思就是:這件事兒需要等待,如果你反復催促,我就重新計時!
空講無益,show you 場景:
- 有個輸入框,輸入之后會調用接口,獲取聯想詞。但是,因為頻繁調用接口不太好,所以我們在代碼中使用防抖功能,只有在用戶輸入完畢的一段時間后,才會調用接口,出現聯想詞。
小伙伴們可以嘗試看着上面的案例,先自己實現一遍這個場景的解決,如果感覺不行,那就看:《防抖和節流的應用場景和實現》
知識點補充:何為
arguments
?
首先,后端轉前端的同學,可以將arguments
理解為能實現重載函數功能的工具。
然后,我們舉個例子:在function test()
這個方法中,由於我們不確定變量有多少,比如test("jsliang", 24)
,又或者test("LiangJunrong", "jsliang", "24")
,這時候只需要在函數test
中用arguments
接收就行了。
最后,在function test() { let arr1 = argument[0] }
中,arr1
就可以獲取到傳進來的第一個變量。
所以,fn.call(this, arguments)
其實是將不確定變量替換到函數中了。
參考資料 1:《閑聊 JS 中的 apply 和 call》
參考資料 2:《js 中 arguments 的用法》
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>demo</title> </head> <body> <input type="text" name="search"> <script type="text/javascript"> var searchInput = document.querySelector('input[name="search"]'); /*綁定事件*/ searchInput.addEventListener('keyup',debounce(getInputValue),false); /* 防抖函數 */ function debounce(fn){ var timer = null; return function(){ if(timer){ clearTimeout(timer) } timer = setTimeout(()=>{ fn.call(this,arguments) },500) } } /* 調用獲取輸入值 */ function getInputValue(){ console.dir(this.value) } </script> </body> </html>
.