<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
前言:
防抖(Debounce) 和 節流(Throttle) 技術用於限制函數執行的次數。通常,一個函數將被執行多少次或何時執行由開發人員決定。但在某些情況下,開發人員會將這種能力賦予使用者,由使用者決定執行該功能的時間和次數。
例如,新增到click
、scroll
、resize
等事件上的函數,允許使用者決定何時執行它們以及執行多少次。有時,使用者可能會比所需更頻繁地執行這些操作。這可能不利於網站的效能,特別是如果附加到這些事件的函數執行一些繁重的計算。在這種情況下,使用者可以控制函數的執行,開發人員必須設計一些技術來限制使用者可以執行函數的次數。
舉個例子,假設我們為捲動事件scroll
新增了一個函數,該函數中會執行修改DOM元素的操作。我們知道,修改DOM元素大小開銷很大,會引起瀏覽器的迴流(Reflow)和重排(Repaint),以及重新渲染整個或部分頁面。如果使用者頻繁捲動,導致該函數頻繁被呼叫,可能會影響網頁效能或導致頁面卡頓等。
此外,有些事件回撥函數中包含ajax等非同步操作的時候,多次觸發會導致返回的內容結果順序不一致,而導致得到的結果非最後一次觸發事件對應的結果
所以,為了優化網頁的效能,控制函數被呼叫的頻率是很有必要的,防抖(Debounce) 和 節流(Throttle) 是通過控制函數被呼叫的頻率來優化指令碼效能的兩種方法
防抖:無論使用者觸發多少次事件,對應的回撥函數只會在事件停止觸發指定事件後執行。(即:回撥函數在事件停止觸發指定時間後被呼叫)
例如,假設使用者在 100 毫秒內點選了 5 次按鈕。防抖技術不會讓這些點選中的任何一個執行對應的回撥函數。一旦使用者停止點選,如果去抖時間為 100 毫秒,則回撥函數將在 100 毫秒後執行。因此,肉眼看來,防抖就像將多個事件組合成一個事件一樣。
觸發事件後函數不會立即執行,而是在停止事件觸發後 n 毫秒後執行,如果在 n 毫秒內又觸發了事件,則會重新計時
/** * @desc 函數防抖 * @param func 回撥函數 * @param delay 延遲執行毫秒數 */ function debounce(func, delay) { let timer; // 定時器 return function () { let context = this; // 記錄 this 值,防止在回撥函數中丟失 let args = arguments; // 函數引數 //如果定時器存在,則清除定時器(如果沒有,也沒必要進行處理) timer ? clearTimeout(timer) : null; timer = setTimeout(() => { // 防止 this 值變為 window func.apply(context, args) }, delay); } }
觸發事件後立即執行回撥函數,但是觸發後n毫秒內不會再執行回撥函數,如果 n 毫秒內觸發了事件,也會重新計時。
/** * @desc 函數防抖 * @param func 回撥函數 * @param delay 延遲執行毫秒數 */ function _debounce(func, delay) { let timer; // 定時器 return function () { let context = this; // 記錄 this 值,防止在回撥函數中丟失 let args = arguments; // 函數引數 // 標識是否立即執行 let isImmediately = !timer; //如果定時器存在,則清除定時器(如果沒有,也沒必要進行處理) timer ? clearTimeout(timer) : null; timer = setTimeout(() => { timer = null; }, delay); // isImmediately 為 true 則 執行函數(即首次觸發事件) isImmediately ? func.apply(context, args) : null; } }
舉個例子來對比一下兩個版本的區別:
document.body.onclick= debounce(function () { console.log('hello') },1000)
如上程式碼中,我們給body新增了一個點選事件監聽器。
hello
,要等 1000ms 後才會列印。在這 1000s 內如果還點選了 body,那麼就會重新計時。即最後一次點選 body 過1000ms後控制檯才會列印hello
hello
,但是在此之後的 1000ms 內點選 body ,控制檯不會有任何反應。在這 1000s 內如果還點選了 body,那麼就會重新計時。必須等計時結束後再點選body,控制檯才會再次列印 hello
。通常,搜尋方塊會提供下拉式選單,為使用者當前的輸入提供自動完成選項。但有時建議項是通過請求後端得到的。可以在實現提示文字時應用防抖,在等待使用者停止輸入一段時間後再顯示建議文字。因此,在每次擊鍵時,都會等待幾秒鐘,然後再給出建議。
window 觸發 resize 的時候,不斷的調整瀏覽器視窗大小會不斷觸發這個事件,用防抖讓其只觸發一次
例如掘金一類的網站,都會內嵌文字編輯器,在編輯過程中會自動儲存文字,防止資料丟失。每次儲存都會與後端進行資料互動,所以可以應用防抖,在使用者停止輸入後一段時間內再自動儲存。
通常對於一些特殊格式的輸入項,我們通常會檢查格式。我們可以應用防抖在使用者停止輸入後一段時間再進行格式檢測,而不是輸入框中內容發生改變就檢測。
節流:無論使用者觸發事件多少次,附加的函數在給定的時間間隔內只會執行一次。(即:回撥函數在規定時間內最多執行一次)
例如,當用戶單擊一個按鈕時,會執行一個在控制檯上列印Hello, world
的函數。現在,假設對這個函數應用 1000 毫秒的限制時,無論使用者點選按鈕多少次,Hello, world
在 1000 毫秒內都只會列印一次。節流可確保函數定期執行。
/** * @desc 函數節流 * @param func 回撥函數 * @param limit 時間限制 */ const throttle = (func, limit) => { let inThrottle; // 是否處於節流限制時間內 return function() { const context = this; const args = arguments; // 跳出時間限制 if (!inThrottle) { func.apply(context, args); // 執行回撥 inThrottle = true; // 開啟定時器計時 setTimeout(() => inThrottle = false, limit); } } }
/** * @desc 函數節流 * @param func 回撥函數 * @param limit 時間限制 */ function throttle(func, limit) { //上次執行時間 let previous = 0; return function() { //當前時間 let now = Date.now(); let context = this; let args = arguments; // 若當前時間-上次執行時間大於時間限制 if (now - previous > limit) { func.apply(context, args); previous = now; } } }
很多現有的庫中已經實現了防抖函數和節流函數
拿王者榮耀為例,通常都有攻速一說。如果攻速低,即使 n 毫秒內點選平A按鈕多次,也只會執行一次平A。其實這裡就類似於節流的思想,可以通過設定節流的時間間隔限制,來改變攻速。
如果捲動事件被觸發得太頻繁,可能會影響效能,因為它包含大量視訊和影象。因此捲動事件必須使用節流
如何選擇防抖和節流:
關於防抖函數和節流函數的選擇,一篇部落格中是這樣建議的:
A debounce is utilized when you only care about the final state. A throttle is best used when you want to handle all intermediate states but at a controlled rate.
即:如果只關心最終狀態,建議使用防抖。如果是想要函數以可控的速率執行,那麼建議使用節流。
延時多久合理:
到此這篇關於JavaScript 防抖debounce與節流thorttle的文章就介紹到這了,更多相關JavaScript 防抖與節流內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45