7

Was bewirkt, dass der Rest der Schleife ausgeführt werden kann und dann für requestAnimationFrame das nächste Frame ausgeführt wird?Warum verursacht der Aufruf von requestAnimationFrame am Anfang einer Schleife keine unendliche Rekursion?

Ich verstehe nicht, wie diese Methode funktioniert und kann nirgends eine klare Erklärung sehen. Ich habe versucht, die Timing-Spezifikation hier http://www.w3.org/TR/animation-timing/ zu lesen, aber ich konnte nicht herausfinden, wie es funktionierte.

Edit:

Zum Beispiel dieser Code von der threejs Dokumentation entnommen wird.

var render = function() { 
requestAnimationFrame(render); 
cube.rotation.x += 0.1; 
cube.rotation.y += 0.1; 
renderer.render(scene, camera); 
}; 
+2

Können Sie bitte einen Code posten? –

+0

[Anfrage Animationsrahmen für bessere Leistung] (http://html5hub.com/request-animation-frame-for-better-performance/), [requestAnimationFrame für Smart Animating] (http://www.paulirish.com/2011/requestanimationframe-for-smart-animating /) – Andreas

+1

requestAnimationFrame ist nicht rekursiv, es ist async (wie ein kurzes setTimeout, aber effizienter) und wird nach dem Rumpf der Funktion ausgeführt, in der es aufgerufen wird. Es macht jedoch wenig Sinn, es zu setzen es in einer for-Schleife. Die Rekursion geschieht in der Renderfunktion, nicht in requestAnimationFrame übrigens, Sie rufen render nicht in render auf. – mpm

Antwort

10

Bitte lassen Sie mich wissen, wenn ich komplett offline bin; Ich habe die Animation noch nie zuvor benutzt. Ein Beispiel, das ich für die Verwendung von requestAnimationFrame sah ist:

(function animloop(){ 
    requestAnimFrame(animloop); 
    render(); 
})(); 

Fragen Sie sich, warum animloop wie es in requestAnimFrame geben wird nicht zu einer Endlosschleife führen, wenn es später genannt?

Dies ist, weil diese Funktion nicht wirklich rekursiv ist. Sie könnten denken, dass animloop sofort aufgerufen wird, wenn Sie requestAnimFrame aufrufen. Nicht so! requestAnimFrame ist asynchron. Die Anweisungen werden also in der Reihenfolge ausgeführt, die Sie sehen. Was das bedeutet ist, dass der Haupt-Thread nicht für den Anruf an requestAnimFrame wartet, um zurück zu kommen, vor der Anruf an render(). So wird render() fast sofort aufgerufen. Allerdings wird der Rückruf (der in diesem Fall animloop ist) sofort nicht genannt. Es kann aufgerufen werden zu einem bestimmten Zeitpunkt in der Zukunft, wenn Sie bereits von der ersten Aufruf an animloop verlassen haben. Dieser neue Aufruf an animloop hat seinen eigenen Kontext und Stapel, da er nicht tatsächlich aus innerhalb der Ausführungskontext der ersten animloop Aufruf aufgerufen wurde. Aus diesem Grund enden Sie nicht mit unendlicher Rekursion und einem Stapelüberlauf.

+1

OK, das macht jetzt mehr Sinn, mein Verständnis von Callbacks ist immer noch wackelig, also muss ich etwas recherchieren. Danke :) – dnv

5

Dieses, was passiert:

Sie eine Funktionsdefinition deklarieren, requestAnimationFrame Funktion aufrufen.

Welche Zeitplan Ihre Funktion wieder aufgerufen und ausgeführt werden, wenn der richtige Zeitpunkt gekommen ist, das ist der Next Rahmen, die in der Regel nach 16 ms ist. Diese Planung ist auch asynchron. Es wird nicht die Ausführung von Code darunter stoppen. Es ist also nicht so, dass Code unterhalb dieser Zeile nicht funktioniert, bis 16ms vergangen sind.

In den meisten Fällen wird die Funktion jedoch innerhalb von 3-4 ms ausgeführt.

Wenn jedoch die Funktion länger dauern würde, würde der nächste Frame verzögert werden, so dass die geplante Task, die dieselbe Funktion wieder aufrufen soll, nicht ausgeführt wird.

In gewisser Hinsicht ist Animation Endlosschleife. Welcher requestAnimationFrame soll sein. Diese nicht blockierende Endlosschleife ist jedoch durch Frames/fps begrenzt.

+0

Basierend auf meinen Tests und begrenztem Verständnis, wartet Raf nicht unbedingt auf den nächsten Frame beim ersten Aufruf. Der Grund, warum es normalerweise fast sofort läuft (0.4ms gerade, als ich in Chrom testete), ist das erste Mal, weil es so schnell läuft, wie es vor dem nächsten Frame möglich ist. Wenn es jedoch in einer rekursiven ish-Schleife aufgerufen wird, werden der zweite und alle nachfolgenden Aufrufe innerhalb der Schleife zur Bildrate entprellt. Ich könnte total falsch liegen, nur meine beste Vermutung darüber, was vor sich geht. Ich habe es nur schwer, dass der Browser einen Frame in 0.4ms rendert. wenn es nicht muss. –

+0

raf versucht, keine Ressourcen zu verschwenden, indem Code ausgeführt wird, der nicht angezeigt wird. Angenommen, Frames werden bei 10ms aktualisiert. und Ihr Code läuft etwa 5 ms. dann sagt dein Code dem Browser, dass er etwas zweimal malen soll, aber es macht nur das letzte, das ist was Raf verhindert .. Wenn der Browser Bilder schneller aktualisieren kann, dann wird der Code schneller ausgeführt. Umgekehrt bedeutet das, dass Ihr Code 20ms dauert und der Browser bei 10ms aktualisiert werden kann. dann hat es keinen Sinn zu aktualisieren, wenn sich nichts geändert hat Browser verzögert das Update. So sparen Sie Computerressourcen. –

1

Aus dem gleichen Grunde, dass mit setTimeout einen Callback-Scheduling wird nicht sofort in einer Schleife unendliche Rekursion verursachen, es Pläne der nächste Anruf auf die JS event loop anstatt ihn auszuführen.

Der Aufruf wird im aktuellen Kontext nicht gemacht, also ist es technisch nicht Rekursion im strengen Sinne des Wortes, und es wird nicht verursachen Stapelgrenze überschritten Fehler.

Event loop diagram

Dieses Diagramm ist für Dart, aber das Konzept ist das gleiche in JS. Wenn Sie mehr über Ereignisschleifen, Zeitplaner und den Unterschied zwischen Mikrotasks und Makrotasks erfahren möchten, lesen Sie this question.

Verwandte Themen