您好,登錄后才能下訂單哦!
這篇文章主要介紹了JavaScript的防抖和節流怎么實現的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇JavaScript的防抖和節流怎么實現文章都會有所收獲,下面我們一起來看看吧。
首先來舉個例子。百度首頁的百度輸入框,用戶輸入的時候,每次輸入的信息,我們都能看到百度服務器返回給我們的聯想關鍵字。我們每改動一個字,它就換一次聯想詞,這是我們肉眼能看到的速度,實際上如果不加以處理,可能已經上服務器發起了好幾十次的同一個關鍵字聯想請求了,具體速度依賴于不同的pc等機器上的運行速度不同。那么,剛剛也談到,對于同一個關鍵字,請求這么多次,也許想給用戶呈現的就一次,剩下的請求都是浪費的,并且如果成千上萬甚至上億的用戶同時請求,對服務器的負擔是巨大的。
防抖節流解決的問題:
在連續觸發的事件中,事件處理函數的頻繁調用會加重瀏覽器或服務器的性能負擔導致用戶體驗糟糕,有哪些連續觸發的事件呢 ?
比如,瀏覽器滾動條的滾動事件、瀏覽器窗口調節的resize事件、輸入框內容校驗以及在移動端的touchmove事件等。
所以,我們將采用防抖函數(debounce )和節流函數(throttle)來限制事件處理函數的調用頻率。
總的來說:防抖函數(debounce )和節流函數(throttle)是在時間軸上控制函數的執行次數。
延遲防抖(debounce): 在事件被觸發n秒后再執行回調,如果在這n秒內又被觸發,則重新計時。
生活中的實例: 如果有人進電梯(觸發事件),那電梯將在10秒鐘后出發(執行事件監聽器),這時如果又有人進電梯了(在10秒內再次觸發該事件),我們又得等10秒再出發(重新計時)。
當持續觸發事件時,一定時間段內沒有再觸發事件,事件處理函數才會執行一次。
如果設定的時間到來之前,又一次觸發了事件,就重新開始延時。
如下圖,持續觸發click事件時,并不執行handle函數,當1000毫秒內沒有觸發click事件時,才會延時觸發click事件。
執行動作在前,然后設定周期,周期內有事件被觸發,不執行動作,且周期重新設定。
為什么要這樣呢?
試想第一種延遲debounce,我們本來想對用戶輸入的關鍵字,發起請求聯想的頻率降低,但是如果用戶在我們設定的時間中,一直輸入,導致的就是,用戶一直看不到關鍵字,我們倒不如第一次輸入的時候就發起一個請求,服務器返回結果,呈現給用戶,然后后續用戶的鍵入結束在繼續請求)。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>防抖</title> </head> <body> <button id="debounce1">點我防抖吶!</button> <script> function handle() { console.log("防抖成功!"); } window.onload = function() { // 1. 獲取按鈕,并綁定事件 var myDebounce = document.getElementById('debounce1'); myDebounce.addEventListener('click',debounce(handle,1000,true)); } // 防抖函數 function debounce(fn,wait, immediate ){ //2. 設置時間戳,使用setTimeout讓返回函數延遲執行 let timer, result; return function(...args){ // 3. timer存在,將定時器中的函數清除 if(timer) clearTimeout(timer); // 4.1 立即執行返回函數 if(immediate){ if(!timer){ result = fn.apply(this,args); } timer = setTimeout(() => { timer = null; },wait); }else{ // 4.2 非立即執行返回函數 timer = setTimeout(() => { fn.apply(this,args); },wait); } } // 5. 立即執行時返回函數的返回值 return result; } </script> </body> </html>
實現效果:
原理解析:
防抖函數作用,對傳入的函數進行延時包裝后返回
setTimeout在前一次未執行完前,第二次次觸發將會覆蓋掉前面的定時器,執行第二次的功能
前一次由于異步加延時還未執行完,使用clearTimeout清除前面定時器,取消上次的fn功能
為保持fn內部this的指向,使用apply改變this指向
fn傳入為函數,不是函數的調用
function debounce(fn,wait, immediate ){ //2. 設置時間戳,使用setTimeout讓返回函數延遲執行 let timer, result; return function(...args){ // 3. timer存在,將定時器中的函數清除 if(timer) clearTimeout(timer); // 4.1 立即執行返回函數 if(immediate){ if(!timer){ result = fn.apply(this,args); } timer = setTimeout(() => { timer = null; },wait); }else{ // 4.2 非立即執行返回函數 timer = setTimeout(() => { fn.apply(this,args); },wait); } } // 5. 立即執行時返回函數的返回值 return result; }
throttling,節流的策略是,固定周期內,只執行一次動作,若有新事件觸發,不執行。周期結束后,又有事件觸發,開始新的周期。 節流策略也分前緣和延遲兩種。
與debounce類似,延遲是指 周期結束后執行動作,前緣是指執行動作后再開始周期。
節流會稀釋函數的執行頻率
在持續觸發事件的過程中,函數會立即執行,并且每n秒執行一次
生活中的實例: 我們知道目前的一種說法是當 1 秒內連續播放 24 張以上的圖片時,在人眼的視覺中就會形成一個連貫的動畫,所以在電影的播放(以前是,現在不知道)中基本是以每秒 24 張的速度播放的,為什么不 100 張或更多是因為 24 張就可以滿足人類視覺需求的時候,100 張就會顯得很浪費資源
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>節流</title> </head> <body> <button id="debounce1">點我節流吶!</button> <script> function handle() { console.log("節流成功!"); } window.onload = function() { var myDebounce = document.getElementById('debounce1'); myDebounce.addEventListener('click',throttling(handle,1000,false)); } // 節流函數 function throttling(fn,wait,immediate){ let timer; return function(...args) { if(!timer){ if(immediate){ fn.apply(this,args); } timer = setTimeout(() => { if(!immediate) { fn.apply(this,args); } timer = null; },wait); } } } </script> </body> </html>
實現效果:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>節流</title> </head> <body> <button id="debounce1">點我節流吶!</button> <script> function handle() { console.log("節流成功!"); } window.onload = function() { var myDebounce = document.getElementById('debounce1'); myDebounce.addEventListener('click',throttling(handle,1000,false)); } // 節流函數 function throttling(fn,wait,immediate){ let timer; return function(...args) { if(!timer){ if(immediate){ fn.apply(this,args); } timer = setTimeout(() => { if(!immediate) { fn.apply(this,args); } timer = null; },wait); } } } </script> </body> </html>
函數節流不管事件觸發有多頻繁,都會保證在規定時間內一定會執行一次真正的事件處理函數。
函數防抖只是在最后一次事件后才觸發一次函數。
比如在頁面的無限加載場景下,我們需要用戶在滾動頁面時,每隔一段時間發一次 Ajax 請求,而不是在用戶停下滾動頁面操作時才去請求數據。這樣的場景,就適合用節流技術來實現。
對于函數防抖,有以下幾種應用場景:
給按鈕加函數防抖防止表單多次提交。
對于輸入框連續輸入進行AJAX驗證時,用函數防抖能有效減少請求次數。
判斷scroll是否滑到底部,滾動事件+函數防抖
總的來說,適合多次事件一次響應的情況
對于函數節流,有如下幾個場景:
游戲中的刷新率
DOM元素拖拽
Canvas畫筆功能
總的來說,適合大量事件按時間做平均分配觸發。
關于“JavaScript的防抖和節流怎么實現”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“JavaScript的防抖和節流怎么實現”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。