JavaScript中的函數大多數狀況下都是由用戶主動調用觸發的,除非是函數自己的實現不合理,不然咱們通常不會遇到跟性能相關的問題。但在一些少數狀況下,函數的觸發不是由用戶直接控制的。在這些場景下,函數有可能被很是頻繁地調用,而形成大的性能問題。下面將列舉一些這樣的場景。瀏覽器
(1) 函數被頻繁調用的場景app
window.onresize
事件。咱們給window
對象綁定了resize
事件,當瀏覽器窗口大小被拖動而改變的時候,這個事件觸發的頻率很是之高。若是咱們在window.onresize
事件函數裏有一些跟DOM節點相關的操做,而跟DOM節點相關的操做每每是很是消耗性能的,這時候瀏覽器可能就會吃不消而形成卡頓現象。函數
mousemove
事件。一樣,若是咱們給一個div
節點綁定了拖曳事件(主要是mousemove
),當div
節點被拖動的時候,也會頻繁地觸發該拖曳事件函數。性能
上傳進度。微雲的上傳功能使用了公司提供的一個瀏覽器插件。該瀏覽器插件在真正開始上傳文件以前,會對文件進行掃描並隨時通知JavaScript函數,以便在頁面中顯示當前的掃描進度。但該插件通知的頻率很是之高,大約一秒鐘10次,很顯然咱們在頁面中不須要如此頻繁地去提示用戶。this
(2) 函數節流的原理spa
咱們整理上面提到的三個場景,發現它們面臨的共同問題是函數被觸發的頻率過高。插件
好比咱們在window.onresize
事件中要打印當前的瀏覽器窗口大小,在咱們經過拖曳來改變窗口大小的時候,打印窗口大小的工做1秒鐘進行了10次。而咱們實際上只須要2次或者3次。這就須要咱們按時間段來忽略掉一些事件請求,好比確保在500ms內只打印一次。很顯然,咱們能夠藉助setTimeout
來完成這件事情。code
(3) 函數節流的代碼實現對象
關於函數節流的代碼實現有許多種,下面的throttle
函數的原理是,將即將被執行的函數用setTimeout
延遲一段時間執行。若是該次延遲執行尚未完成,則忽略接下來調用該函數的請求。throttle
函數接受2個參數,第一個參數爲須要被延遲執行的函數,第二個參數爲延遲執行的時間。具體實現代碼以下:blog
var throttle = function ( fn, interval ) { var __self = fn, // 保存須要被延遲執行的函數引用 timer, // 定時器 firstTime = true; // 是不是第一次調用 return function () { var args = arguments, __me = this; if ( firstTime ) { // 若是是第一次調用,不需延遲執行 __self.apply(__me, args); return firstTime = false; } if ( timer ) { // 若是定時器還在,說明前一次延遲執行尚未完成 return false; } timer = setTimeout(function () { // 延遲一段時間執行 clearTimeout(timer); timer = null; __self.apply(__me, args); }, interval || 500 ); }; }; window.onresize = throttle(function(){ console.log( 1 ); }, 500 );