Heim  >  Artikel  >  Web-Frontend  >  JavaScript-Leistungsoptimierung: Funktionsdrosselung (throttle) und Funktionsentprellung (debounce)

JavaScript-Leistungsoptimierung: Funktionsdrosselung (throttle) und Funktionsentprellung (debounce)

高洛峰
高洛峰Original
2016-12-29 10:08:361455Durchsuche

Funktionsdrosselung bedeutet vereinfacht gesagt, dass eine Funktion nicht kontinuierlich innerhalb eines kurzen Zeitintervalls aufgerufen werden kann. Erst wenn das von Ihnen angegebene Zeitintervall seit der letzten Funktionsausführung verstrichen ist, kann der nächste Funktionsaufruf erfolgen.

Das Prinzip der Funktionsdrosselung ist ziemlich einfach, daran hat wohl jeder gedacht, das ist der Timer. Wenn ich eine Zeit auslöse, setze ich zunächst Timeout, um das Ereignis um eine Weile zu verzögern, und führe es dann aus. Wenn das Ereignis innerhalb dieses Zeitintervalls erneut ausgelöst wird, löschen wir den ursprünglichen Timer und setzen dann einen neuen Timer, um die Ausführung um eine Weile zu verzögern . , das ist alles.

Die folgenden Szenarien werden häufig durch häufige Ereignisse ausgelöst, sodass häufig DOM-Vorgänge, das Laden von Ressourcen und andere schwere Aktivitäten ausgeführt werden, was zu Pausen der Benutzeroberfläche oder sogar Browserabstürzen führt.

1. Die Größenänderungs- und Bildlaufereignisse des Fensterobjekts

2. Das Mausbewegungsereignis beim Ziehen

3 Mousedown, Keydown-Ereignisse

4. Texteingabe, automatisch abgeschlossene Keyup-Ereignisse

Tatsächlich besteht die eigentliche Anforderung bei Fenstergrößenänderungsereignissen hauptsächlich darin, die Änderung der Größe n zu stoppen Millisekunden später Führen Sie eine Folgeverarbeitung durch, während die meisten anderen Ereignisse eine Folgeverarbeitung in einer bestimmten Häufigkeit erfordern. Als Reaktion auf diese beiden Anforderungen sind zwei Lösungen entstanden: Entprellen und Drosseln.

Drosseln und Entprellen sind zwei Lösungen, um das Problem der Nichtübereinstimmung von Anforderungs- und Antwortgeschwindigkeit zu lösen. Der Unterschied zwischen beiden liegt in der Wahl unterschiedlicher Strategien.

Gas: Führen Sie die Funktion in gleichen Zeitintervallen aus.

Entprellen Wenn das Ereignis innerhalb des Zeitintervalls t erneut ausgelöst wird, wird die Zeit neu gestartet und die Funktion erst dann ausgeführt, wenn die Stoppzeit größer oder gleich t ist.

1. Einfache Implementierung der Drosselfunktion

function throttle(fn, threshhold, scope) { 
threshhold || (threshhold = 250); 
var last, 
timer; return function () { 
var context = scope || this; 
var now = +new Date(), 
args = arguments; 
if (last && now - last + threshhold < 0) { 
// hold on to it 
clearTimeout(deferTimer); 
timer = setTimeout(function () { 
last = now; 
fn.apply(context, args); 
}, threshhold); 
} else { 
last = now; 
fn.apply(context, args); 
} 
};}

Aufrufmethode

$(&#39;body&#39;).on(&#39;mousemove&#39;, throttle(function (event) 
{
console.log(&#39;tick&#39;);
}, 1000));

2. Einfache Implementierung der Entprellfunktion

function debounce(fn, delay) 
{ 
var timer = null; 
return function () 
{ 
var context = this,
args = arguments; 
clearTimeout(timer); 
timer = setTimeout(function () { 
fn.apply(context, args); 
}, delay); 
};}

Aufrufmethode

$(&#39;input.username&#39;).keypress(debounce(function (event)
{
// do the Ajax request
}, 250));

3. Einfache Kapselungsimplementierung

/** * throttle * @param fn, wait, debounce */var throttle = function ( fn, wait, debounce ) { 
var timer = null, // 定时器 
t_last = null, // 上次设置的时间 
context, // 上下文 
args, // 参数 
diff; // 时间差 
return funciton () { 
var curr = + new Date(); 
var context = this, args = arguments; 
clearTimeout( timer ); 
if ( debounce ) { // 如果是debounce 
timer = setTimeout( function () { 
fn.apply( context, args ); 
}, wait ); 
} else { // 如果是throttle 
if ( !t_last ) t_last = curr; 
if ( curr - t_last >= wait ) { 
fn.apply( context, wait ); 
context = wait = null; 
} 
} }}/** * debounce * @param fn, wait */var debounce = function ( fn, wait ) 
{ 
return throttle( fn, wait, true );
}

Zusammenfassung: Diese beiden Methoden eignen sich für einige Ereignisse, die wiederholt ausgelöst werden, wie zum Beispiel: Mausbewegung, Tastendruck, Tastendruck, Tastendruck, Scrollen usw.
Wenn Sie nur native Ereignisse binden, ohne sie zu steuern, friert der Browser ein und die Benutzererfahrung wird schlecht. Um die Leistung von js zu verbessern, wird empfohlen, bei Verwendung der oben genannten und ähnlicher Ereignisse die Funktionsdrosselung oder Funktionsentprellung zur Steuerung zu verwenden.

4. Quellcode-Analyse im Zusammenhang mit Underscore v1.7.0

1. _.throttle-Funktion

_.throttle = function(func, wait, options) { 
var context, args, result; 
var timeout = null; 
// 定时器 
var previous = 0; 
// 上次触发的时间 
if (!options) options = {}; 
var later = function() { 
previous = options.leading === false ? 0 : _.now(); 
timeout = null; 
result = func.apply(context, args); 
if (!timeout) context = args = null; 
}; 
return function()
{ 
var now = _.now(); 
// 第一次是否执行 
if (!previous && options.leading === false) previous = now; 
// 这里引入了一个remaining的概念:还剩多长时间执行事件 
var remaining = wait - (now - previous); 
context = this; 
args = arguments; 
// remaining <= 0 考虑到事件停止后重新触发或者 
// 正好相差wait的时候,这些情况下,会立即触发事件 
// remaining > wait 没有考虑到相应场景 
// 因为now-previous永远都是正值,且不为0,那么 
// remaining就会一直比wait小,没有大于wait的情况 
// 估计是保险起见吧,这种情况也是立即执行 
if (remaining <= 0 || remaining > wait) 
{ 
if (timeout)
{ 
clearTimeout(timeout); 
timeout = null; 
} 
previous = now; 
result = func.apply(context, args); 
if (!timeout) context = args = null; 
// 是否跟踪 
} else if (!timeout && options.trailing !== false)
{ 
timeout = setTimeout(later, remaining); 
} 
return result; 
};};

Wie aus dem hervorgeht Oben berücksichtigt der Unterstrich häufigere Situationen: options.leading:

Ob zum ersten Mal ausgeführt werden soll Der Standardwert ist true, was bedeutet, dass {leading:false übergeben wird } deaktiviert die erste Ausführung von Optionen: Der Standardwert ist „true“, was bedeutet, dass sie zum letzten Mal ausgeführt werden Die sogenannte „Ob zum ersten Mal ausführen“ bedeutet, ob das Ereignis zuerst ausgelöst werden soll. Wenn dies erforderlich ist, ist previous=0 und der Rest ist ein negativer Wert. Das sogenannte „Ob das letzte Mal ausgeführt werden soll“ ist das letzte Mal, dass diese Methode nach dem Ende des Ereignisses ausgelöst wird. Wenn sie ausgeführt werden soll, wird der Timer festgelegt, d. h. sie wird nach dem Ende des Ereignisses einmal ausgeführt. Remaining > Wait zeigt an, dass die Clientzeit geändert wurde.

2. _.debounce-Funktion

_.debounce = function(func, wait, immediate) { 
// immediate默认为false 
var timeout, args, context, timestamp, result; 
var later = function() { 
// 当wait指定的时间间隔期间多次调用_.debounce返回的函数,则会不断更新timestamp的值,导致last < wait && last >= 0一直为true,从而不断启动新的计时器延时执行func var last = _.now() - timestamp; 
if (last < wait && last >= 0) { 
timeout = setTimeout(later, wait - last); 
} else { 
timeout = null; 
if (!immediate) { 
result = func.apply(context, args); 
if (!timeout) context = args = null; 
} 
} 
}; 
return function() 
{ 
context = this; 
args = arguments; 
timestamp = _.now(); 
// 第一次调用该方法时,且immediate为true,则调用func函数 
var callNow = immediate && !timeout; // 在wait指定的时间间隔内首次调用该方法,则启动计时器定时调用func函数 
if (!timeout) timeout = setTimeout(later, wait); 
if (callNow) { 
result = func.apply(context, args); 
context = args = null; 
} 
return result; 
};};

Ich denke, das Wunderbare an _.debounce ist, dass es den Timer rekursiv startet, anstatt die Verzögerung des Aufrufs der Funktion func durch den Aufruf von clearTimeout anzupassen implementieren.

Das Obige ist die vom Herausgeber eingeführte Funktion zur Optimierung der JavaScript-Leistung. Wenn Sie Fragen haben, hinterlassen Sie mir bitte eine Nachricht Ich werde allen rechtzeitig antworten. Ich möchte mich auch bei Ihnen allen für Ihre Unterstützung der chinesischen PHP-Website bedanken!

Weitere Artikel zum Thema Drosselung der JavaScript-Leistungsoptimierungsfunktion (Throttle) und Funktionsentprellung (Debounce) finden Sie auf der chinesischen PHP-Website!


Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn