日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > HTML >内容正文

HTML

前端性能优化之防抖-debounce

發布時間:2024/9/21 HTML 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 前端性能优化之防抖-debounce 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

這周接到一個需求-給輸入框做模糊匹配。這還不簡單,監聽input事件,取到輸入值去調接口不就行了? 然而后端小哥說不行,這個接口的數據量非常大,這種方式調用接口的頻率太高,而且用戶輸入時調用根本沒有必要,只要在用戶停止輸入的那一刻切調接口就行了。 唉?這個場景聽起來怎么這么像防抖呢?

那到底什么是防抖呢? 大家一定見過那種左右兩邊中間放廣告位的網站,在網頁滾動時,廣告位要保持在屏幕中間,就要不斷地去計算位置,如果不做限制,在視覺上廣告位就像在“抖”。防止這種情況,就叫防抖了!

防抖的原理是什么? 我一直覺得網上流傳的例子非常形象:當我們在乘電梯時,如果這時有人過來,我們會出于禮貌一直按著開門按鈕等待,等到這人進電梯了,剛準備關門時,發現又有人過來了!我們又要重復之前的操作,如果電梯空間無限大的話,我們就要一直等待了。。。當然人的耐心是有限的!所以我們規定了一個時間,比如10秒,如果10秒都沒人來的話,就關電梯門。

用專業術語概括就是:在一定時間間隔內函數被觸發多次,但只執行最后一次。

最簡易版的代碼實現:

function debounce(fn, delay) {let timer = null;return function() {const context = this;const args = arguments;if (timer) {clearTimeout(timer);timer = null;}timer = setTimeout(() => {fn.apply(context, args);}, delay);}; } 復制代碼

fn是要進行防抖的函數,delay是設定的延時,debounce返回一個匿名函數,形成閉包,內部維護了一個私有變量timer。我們一直會觸發的是這個返回的匿名函數,定時器會返回一個Id值賦給timer,如果在delay時間間隔內,匿名函數再次被觸發,定時器都會被清除,然后重新開始計時。

當然簡易版肯定不能滿足日常的需求,比如可能需要第一次立即執行的,所以要稍做改動:

function debounce(fn, delay, immediate) {let timer = null;return function() {const context = this;const args = arguments;timer && clearTimeout(timer);if(immediate) {const doNow = !timer;timer = setTimeout(() => {timer = null;}, delay);doNow && fn.apply(context, args);}else {timer = setTimeout(() => {fn.apply(context, args);}, delay);}}; } 復制代碼

比起簡易版,多了個參數immediate來區分是否需要立即執行。其它與簡易版幾乎一致的邏輯,除了判斷立即執行的地方:

const doNow = !timer;timer = setTimeout(() => {timer = null; }, delay);doNow && fn.apply(context, args); 復制代碼

doNow變量的值為!timer,只有!timer為true的情況下,才會執行fn函數。第一次執行時,timer的初始值為null,所以會立即執行fn。接下來非第一次執行的情況下,等待delay時間后才能再次觸發執行fn。 注意!與簡易版的區別,簡易版是一定時間多次內觸發,執行最后一次。而立即執行版是不會執行最后一次的,需要再次觸發。

防抖的函數可能是有返回值,我們也要做兼容:

function debounce(fn, delay, immediate) {let timer = null;return function() {const context = this;const args = arguments;let result = undefined;timer && clearTimeout(timer);if (immediate) {const doNow = !timer;timer = setTimeout(() => {timer = null;}, delay);if (doNow) {result = fn.apply(context, args);} }else {timer = setTimeout(() => {fn.apply(context, args);}, delay);}return result;}; } 復制代碼

但是這個實現方式有個缺點,因為除了第一次立即執行,其它情況都是在定時器中執行的,也就是異步執行,返回值會是undefined。

考慮到異步,我們也可以返回Promise:

function debounce(fn, delay, immediate) {let timer = null;return function() {const context = this;const args = arguments;return new Promise((resolve, reject) => {timer && clearTimeout(timer);if (immediate) {const doNow = !timer;timer = setTimeout(() => {timer = null;}, delay);doNow && resolve(fn.apply(context, args));}else {timer = setTimeout(() => {resolve(fn.apply(context, args));}, delay);}});}; } 復制代碼

如此,只要fn被執行,那必定可以拿到返回值!這也是防抖的終極版了!

下次聊聊防抖的兄弟-前端性能優化之節流-throttle。

總結

以上是生活随笔為你收集整理的前端性能优化之防抖-debounce的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。