摘要:函數節流的原理函數節流的原理挺簡單的,估計大家都想到了,那就是定時器。在高級程序設計一書有介紹函數節流,里面封裝了這樣一個函數節流函數,它把定時器存為函數的一個屬性個人的世界觀不喜歡這種寫法。
什么是函數節流?
介紹前,先說下背景。在前端開發中,有時會為頁面綁定resize事件,或者為一個頁面元素綁定拖拽事件(其核心就是綁定mousemove),這種事件有一個特點,就是用戶不必特地搗亂,他在一個正常的操作中,都有可能在一個短的時間內觸發非常多次事件綁定程序。而大家知道,DOM操作時很消耗性能的,這個時候,如果你為這些事件綁定一些操作DOM節點的操作的話,那就會引發大量的計算,在用戶看來,頁面可能就一時間沒有響應,這個頁面一下子變卡了變慢了。甚至在IE下,如果你綁定的resize事件進行較多DOM操作,其高頻率可能直接就使得瀏覽器崩潰。
怎么解決?函數節流就是一種辦法。話說第一次接觸函數節流(throttle),還是在看impress源代碼的時候,impress在播放的時候,如果窗口大小發生改變(resize),它會對整體進行縮放(scale),使得每一幀都完整顯示在屏幕上:
稍微留心,你會發現,當你改變窗體大小的時候,不管你怎么拉,怎么拽,都沒有立刻生效,而是在你改變完大小后的一會兒,它的內容才進行縮放適應。看了源代碼,它用的就是函數節流的方法。
函數節流,簡單地講,就是讓一個函數無法在很短的時間間隔內連續調用,只有當上一次函數執行后過了你規定的時間間隔,才能進行下一次該函數的調用。以impress上面的例子講,就是讓縮放內容的操作在你不斷改變窗口大小的時候不會執行,只有你停下來一會兒,才會開始執行。
函數節流的原理函數節流的原理挺簡單的,估計大家都想到了,那就是定時器。當我觸發一個時間時,先setTimout讓這個事件延遲一會再執行,如果在這個時間間隔內又觸發了事件,那我們就clear掉原來的定時器,再setTimeout一個新的定時器延遲一會執行,就這樣。
代碼實現明白了原理,那就可以在代碼里用上了,但每次都要手動去新建清除定時器畢竟麻煩,于是需要封裝。在《JavaScript高級程序設計》一書有介紹函數節流,里面封裝了這樣一個函數節流函數:
function throttle(method, context) { clearTimeout(methor.tId); method.tId = setTimeout(function(){ method.call(context); }, 100); }
它把定時器ID存為函數的一個屬性(= =個人的世界觀不喜歡這種寫法)。而調用的時候就直接寫
window.onresize = function(){ throttle(myFunc); }
這樣兩次函數調用之間至少間隔100ms。
而impress用的是另一個封裝函數:
var throttle = function(fn, delay){ var timer = null; return function(){ var context = this, args = arguments; clearTimeout(timer); timer = setTimeout(function(){ fn.apply(context, args); }, delay); }; };
它使用閉包的方法形成一個私有的作用域來存放定時器變量timer。而調用方法為
window.onresize = throttle(myFunc, 100);
兩種方法各有優劣,前一個封裝函數的優勢在把上下文變量當做函數參數,直接可以定制執行函數的this變量;后一個函數優勢在于把延遲時間當做變量(當然,前一個函數很容易做這個拓展),而且個人覺得使用閉包代碼結構會更優,且易于拓展定制其他私有變量,缺點就是雖然使用apply把調用throttle時的this上下文傳給執行函數,但畢竟不夠靈活。
深化函數節流函數節流讓一個函數只有在你不斷觸發后停下來歇會才開始執行,中間你操作得太快它直接無視你。這樣做就有點太絕了。resize一般還好,但假如你寫一個拖拽元素位置的程序,然后直接使用函數節流,那恭喜你,你會發現你拖動時元素是不動的,你拖完了,它直接閃到終點去。
其實函數節流的出發點,就是讓一個函數不要執行得太頻繁,減少一些過快的調用來節流。當你改變瀏覽器大小,瀏覽器觸發resize事件的時間間隔是多少?我不清楚,個人猜測是16ms(每秒64次),反正跟mousemove一樣非常太頻繁,一個很小的時間段內必定執行,這是瀏覽器設好的,你無法直接改。而真正的節流應該是在可接受的范圍內盡量延長這個調用時間,也就是我們自己控制這個執行頻率,讓函數減少調用以達到減少計算、提升性能的目的。假如原來是16ms執行一次,我們如果發現resize時每50ms一次也可以接受,那肯定用50ms做時間間隔好一點。
而上面介紹的函數節流,它這個頻率就不是50ms之類的,它就是無窮大,只要你能不間斷resize,刷個幾年它也一次都不執行處理函數。我們可以對上面的節流函數做拓展:
var throttleV2 = function(fn, delay, mustRunDelay){ var timer = null; var t_start; return function(){ var context = this, args = arguments, t_curr = +new Date(); clearTimeout(timer); if(!t_start){ t_start = t_curr; } if(t_curr - t_start >= mustRunDelay){ fn.apply(context, args); t_start = t_curr; } else { timer = setTimeout(function(){ fn.apply(context, args); }, delay); } }; };
在這個拓展后的節流函數升級版,我們可以設置第三個參數,即必然觸發執行的時間間隔。如果用下面的方法調用
window.onresize = throttleV2(myFunc, 50, 100);
則意味著,50ms的間隔內連續觸發的調用,后一個調用會把前一個調用的等待處理掉,但每隔100ms至少執行一次。原理也很簡單,打時間tag,一開始記錄第一次調用的時間戳,然后每次調用函數都去拿最新的時間跟記錄時間比,超出給定的時間就執行一次,更新記錄時間。
到現在為止呢,當我們在開發中遇到類似的問題,一個函數可能非常頻繁地調用,我們有了幾個選擇:一呢,還是用原來的寫法,頻繁執行就頻繁執行吧,哥的電腦好;二是用原始的函數節流;三則是用函數節流升級版。不是說第一種就不好,這要看實際項目的要求,有些就是對實時性要求高。而如果要求沒那么苛刻,我們可以視具體情況使用第二種或第三種方法,理論上第二種方法執行的函數調用最少,性能應該節省最多,而第三種方法則更加地靈活,你可以在性能與體驗上探索一個平衡點。
轉載自AlloyTeam:http://www.alloyteam.com/2012...
擴展閱讀:JS魔法堂:函數節流(throttle)與函數去抖(debounce)
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/83095.html
摘要:主要實現思路就是通過定時器,通過設置延時時間,在第一次調用時,創建定時器,寫入需要執行的函數。如果這時前一個定時器暫未執行,則將其替換為新的定時器。 JS中的函數節流 一、什么是函數節流(throttle) 概念:限制一個函數在一定時間內只能執行一次。 舉個栗子,坐火車或地鐵,過安檢的時候,在一定時間(例如10秒)內,只允許一個乘客通過安檢入口,以配合安檢人員完成安檢工作。上例中,每1...
摘要:目的都是為了降低回調函數執行頻率,節省計算機資源,優化性能,提升用戶體驗。函數防抖事件頻繁觸發的情況下,只有經過足夠的空閑時間,才執行代碼一次。 函數節流和函數防抖的對比分析 一、前言 前端開發中,函數節流(throttle) 和 函數防抖(debounce) 作為常用的性能優化方法,兩者都是用于優化高頻率執行 js 代碼的手段,那具體它們有什么異同點呢?有對這兩個概念不太了解的小伙伴...
摘要:引言上一節我們詳細聊了聊高階函數之柯里化,通過介紹其定義和三種柯里化應用,并在最后實現了一個通用的函數。第二種方案來實現也存在一個問題,因為定時器是延遲執行的,所以事件停止觸發時必然會響應回調,所以時無法生效。 引言 上一節我們詳細聊了聊高階函數之柯里化,通過介紹其定義和三種柯里化應用,并在最后實現了一個通用的 currying 函數。這一小節會繼續之前的篇幅聊聊函數節流 thrott...
摘要:相反,在討論時,面試中通常會提到三件事。通過對事件對應的回調函數進行包裹以自由變量的形式緩存時間信息,最后用來控制事件的觸發頻率。而認為最后一個參賽者說了算,只要還能吃的,就重新設定新的定時器。 showImg(https://segmentfault.com/img/bVboH5x?w=1000&h=750); 想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等著你! 本...
摘要:譯通過實例講解和防抖與節流源碼中推薦的文章,為了學習英語,翻譯了一下原文鏈接作者本文來自一位倫敦前端工程師的技術投稿。首次或立即你可能發現防抖事件在等待觸發事件執行,直到事件都結束后它才執行。 [譯]通過實例講解Debouncing和Throtting(防抖與節流) lodash源碼中推薦的文章,為了學習(英語),翻譯了一下~ 原文鏈接 作者:DAVID CORBACHO 本文來自一位...
閱讀 2731·2021-11-24 09:39
閱讀 1647·2021-09-28 09:35
閱讀 1119·2021-09-06 15:02
閱讀 1307·2021-07-25 21:37
閱讀 2726·2019-08-30 15:53
閱讀 3643·2019-08-30 14:07
閱讀 714·2019-08-30 11:07
閱讀 3512·2019-08-29 18:36