摘要:節流和防抖都是用來提高用戶體驗,提高網站性能的手段,它們的技術手段都是強制事件處理函數在特定的事件段內執行。針對上面舉例的情況,其實運用節流和防抖都可以做到,只是它們之間又有一定的區別節流節流是在一定的時間段內,函數最多可以被調用多少次。
“節流”和“防抖”都是用來提高用戶體驗,提高網站性能的手段,它們的技術手段都是“強制事件處理函數在特定的事件段內執行”。這樣解釋可能還是不夠直觀。舉兩個例子吧:
1: 比方說我們給document綁定了一個scroll的事件,scroll事件是每滑動一個px,scroll的處理函數就會被調用執行,如果在你的處理函數里面恰巧做了一個很花時間或者很花空間的事情,比方說復雜的運算啊,ajax請求啊,那這樣頁面就可能出現卡頓的情況。
2: 頁面上有個地址的輸入框,你希望根據客戶的輸入內容,去幫客戶補全。假如說這個地址列表需要通過ajax請求來獲取,那我們一定是希望在客戶停止輸入了之后再去請求ajax然后來補全,而不是客戶一邊輸入就一直請求ajax。
針對上面舉例的情況,其實運用節流和防抖都可以做到,只是它們之間又有一定的區別:
節流:節流是在一定的時間段內,函數最多可以被調用多少次。也可以理解為函數以一定的頻率被調用。
防抖:防抖是每次想要執行這個函數,都得事先等上一段時間。
語言總是這樣蒼白,直接來看代碼的實現吧。我們先來實現一個防抖:
//實現防抖函數 function debouncing(fn, waitTime){ let timer = undefined; return function(){ let context = this; let args = arguments; clearTimeout(timer); timer = setTimeout(function(){ fn.apply(context, args); }, waitTime) } } //scroll事件的處理函數 function scrollHandler(event){ console.log(new Date(event.timeStamp)); } //document的scroll事件上使用防抖函數 document.addEventListener("scroll", debouncing(scrollHandler,100), false);
實現防抖函數的核心就是每次事件被觸發的時候,我們不是立即去調用相應的handler,而是每一次都重新設置一個timeout,等待一段時間,然后再執行我們的handler.
2: 現在來嘗試實現一個節流函數:
function throttling(fn, intervalTime){ let inInterval = false; return function(){ let context = this; let args = arguments; if(!inInterval) { fn.apply(context, args); inInterval = true; setTimeout(function(){ inInterval = false; }, intervalTime) } } } function scrollHandler(event){ console.log(new Date(event.timeStamp)); } document.addEventListener("scroll", throttling(scrollHandler,500), false);
節流的核心是管理一個布爾值開關變量(inInterval),在某種條件下切換它的true值和false值,而真正的事件處理函數只在這個開關變量的某一個值的時候才執行,從而達到節流的目的。
節流函數它的實現有很多種,多種就在于控制這個開關變量的值的條件,會不一樣。在上面的例子里,我通過setTimeout的方式,間斷性的來改變inInterval的值。
現在來詳細分析一下上面的實現:
1: 第一次scroll事件觸發的時候,scrollHandler就被立即執行了,這個是我個人的一個考慮,希望對于第一次的事件觸發能馬上有一個回饋給客戶。
2: 但是當第一次執行完了之后,我們馬上把"inInterval=true", 假如這時候第二次scroll觸發,代碼執行到 if(!inInterval),因為條件表達式為false,所以scrollHandler不會被立即執行。那可能之后的第三次,第四次。。。scroll事件觸發的時候,inInterval都是true,都不會執行處理函數。
3: 我們之前在把inInterval設置為true之后,同時設置了一個timeout,在經過一定的時間(intervalTime)之后,inInterval會被設置為false; 假如在這之后馬上又觸發了一次scroll事件,代碼走到if(!inInterval),條件為true,scrollHandler就可以被執行了。
但是上面的代碼存在一個問題,假如我們最后一次的scroll事件,正好發生在這個循環時間內,那它就永遠得不到執行了。這個可能會是一個隱藏的bug, 比方說你在進行一次拖拽事件,那目標元素可能永遠都拖不到目的地。
所以我們要改一下代碼,讓最后一次事件能被執行:
function throttling(fn, intervalTime){ let inInterval = false; let lastTimer = undefined; let timer = undefined; return function(){ let context = this; let args = arguments; if(!inInterval) { clearTimeout(lastTimer); //這行代碼很重要 fn.apply(context, args); inInterval = true; timer = setTimeout(function(){ inInterval = false; }, intervalTime) }else{ clearTimeout(lastTimer); lastTimer = setTimeout(function(){ fn.apply(fn, args); inInterval = false; }, intervalTime); } } } function scrollHandler(event){ console.log(new Date(event.timeStamp)); } document.addEventListener("click", throttling(scrollHandler,1000), false);
上面的代碼,要特別解釋一下一下這一行代碼:clearTimeout(lastTimer); //這行代碼很重要
如果我們不加這行代碼的話,會出現先點擊的click事件反而后執行的問題。比如;我們的intervalTime設置為10s, 然后我們分別在第0s, 第5秒,第12秒都進行一次點擊,我們通過console.log(new Date(event.timeStamp)) 打印每一次事件發生時的時間, 我們會看到第5秒的那個click事件會比第12秒的那個click后輸出,這就說明這里有問題。
所以我們要在if(!inInterval){}里面把lastTimer給清掉,也就是通過clearTimeout(lastTimer); 這行代碼。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/83768.html
摘要:封裝方法也比較簡單,書中對此問題也進行了處理使用定時器,讓函數延遲秒后執行,在此秒內,然后函數再次被調用,則刪除上次的定時器,取消上次調用的隊列任務,重新設置定時器。 在實際開發中,函數一定是最實用最頻繁的一部分,無論是以函數為核心的函數式編程,還是更多人選擇的面向對象式的編程,都會有函數的身影,所以對函數進行深入的研究是非常有必要的。 函數節流 比較直白的說,函數節流就是強制規定一...
摘要:相反,在討論時,面試中通常會提到三件事。而認為最后一個參賽者說了算,只要還能吃的,就重新設定新的定時器。試想,如果用戶的操作十分頻繁他每次都不等設置的時間結束就進行下一次操作,于是每次都為該用戶重新生成定時器,回調函數被延遲了不計其數次。本文不是討論最新的 JavaScript 庫、常見的開發實踐或任何新的 ES6 函數。相反,在討論 JavaScript 時,面試中通常會提到三件事。我自己...
摘要:更高效的解決方案是將一個事件偵聽器實際綁定到父容器上,然后在實際單擊時可以訪問每個確切元素。如果將事件偵聽器綁定到窗口滾動事件上,并且用戶快速滾動頁面,事件很可能會在短時間多次觸發。 原文鏈接 問題 #1: 事件委托 事件委托,也叫事件委派,事件代理。 當構建應用程序時,有時需要將事件監聽器綁定到頁面上的某些元素上,以便在用戶與元素交互時執行某些操作。 假設我們現在有一個無序列表: ...
摘要:譯通過實例講解和防抖與節流源碼中推薦的文章,為了學習英語,翻譯了一下原文鏈接作者本文來自一位倫敦前端工程師的技術投稿。首次或立即你可能發現防抖事件在等待觸發事件執行,直到事件都結束后它才執行。 [譯]通過實例講解Debouncing和Throtting(防抖與節流) lodash源碼中推薦的文章,為了學習(英語),翻譯了一下~ 原文鏈接 作者:DAVID CORBACHO 本文來自一位...
閱讀 2211·2021-11-22 13:54
閱讀 3376·2019-08-29 12:25
閱讀 3440·2019-08-28 18:29
閱讀 3579·2019-08-26 13:40
閱讀 3275·2019-08-26 13:32
閱讀 955·2019-08-26 11:44
閱讀 2228·2019-08-23 17:04
閱讀 2968·2019-08-23 17:02