函數被頻繁調用場景 Js中的函數大多數情況下都是由用戶主動調用觸發的,一般不會遇到性能相關的問題。但在一些少數情況下,函數的觸發不是由用戶直接控制。在這些場景下,函數有可能被非常頻繁地調用,而造成大的性能問題。 比如以下場景: 函數節流的原理: 函數節流的原理就是使用定時器來控制函數調用。當觸發一個 ...
函數被頻繁調用場景
Js中的函數大多數情況下都是由用戶主動調用觸發的,一般不會遇到性能相關的問題。但在一些少數情況下,函數的觸發不是由用戶直接控制。在這些場景下,函數有可能被非常頻繁地調用,而造成大的性能問題。
比如以下場景:
- window.onresize事件。如果我們給window對象綁定了resize事件,當瀏覽器視窗大小被改變的時候,這個事件的觸發的頻率非常高。(其實任何元素節點也是可以綁定resize事件的,如何實現可參考 如何給div綁定resize事件。也可以使用第三方庫 resize-observer-polyfill)
- mousemove事件。
- DOM變化觀察者MutationObserver。dom的變化造成觀察者對象被頻繁觸發。
函數節流的原理:
函數節流的原理就是使用定時器來控制函數調用。當觸發一個事件函數時,先setTimout讓這個事件延遲一會再執行,如果在這個時間間隔內又觸發了事件,那我們就clear掉原來的定時器,再setTimeout一個新的定時器延遲一會執行。
代碼實現
var throttle=function(fn,interval){ var _self=fn; //保存需要被延長執行的函數引用 var timer; var firstTime=true; //是否是第一次調用 return function (){ var args=arguments; var _this=this; if(firstTime){ //如果第一次調用,不需要延遲執行 _self.apply(_this,args); return firstTime = false; } if(timer){ //如果定時器還在,說明前一次延遲執行還沒有完成 return false; } timer = setTimeout(function(){ //延遲一段時間執行 clearTimeout(timer); timer=null; _self.apply(_this,args); },interval || 500); }; };View Code 方式1
var throttle2 = function (callback, delay, trailingTimeout) { var leadingCall = false, trailingCall = false, lastCallTime = 0; function resolvePending() { if (leadingCall) { leadingCall = false; callback(); } if (trailingCall) { proxy(); } } function timeoutCallback() { requestAnimationFrame(resolvePending); } function proxy() { var timeStamp = Date.now(); if (leadingCall) { if (timeStamp - lastCallTime < trailingTimeout) { return; } trailingCall = true; } else { leadingCall = true; trailingCall = false; setTimeout(timeoutCallback, delay); } lastCallTime = timeStamp; } return proxy; };View Code 方式2
代碼測試
window.onresize=throttle(function(){ console.log(1); },1000);