Ich wurde (von einem Freund) gebeten, einen Timer zu erstellen (unendlich, der jede Sekunde eine Zeile schreibt), aber ohne setInterval
.
I löste es mit:
%Vor%Und es funktioniert.
Das Problem ist, dass ich befürchte, dass es einen Erinnerungsdruck geben wird. Es erzeugt tatsächlich eine Rekursion und nach einer Weile (Woche oder so) - der Prozess wird viel Speicher verbrauchen. (Der Stapel wird nie freigegeben)
Wie kann ich meinen Code ändern, um nicht viel Speicherverbrauch zu haben?
Es kann wie Rekursion aussehen, aber setTimeout erstellt keine Rekursion.
Die Art und Weise, wie setTimeout funktioniert, ist, dass es sofort zurückkehrt. Der Aufruf von k
endet also sofort mit der Freigabe seines Stacks.
Wenn die Zeitüberschreitung tatsächlich eintritt und der Aufruf von go
erneut auftritt, erfolgt dies nicht von dem Punkt des vorherigen Aufrufs von k
, sondern vom globalen Bereich *.
* Hinweis: Ich verwende hier nicht die strikte Bedeutung des Bereichs, wie in der ECMAScript-Spezifikation definiert. Was ich meine ist, dass der Aufruf von k
so erfolgt, als ob Sie ihn in ein einfaches <script></script>
-Tag geschrieben hätten: das heißt, außerhalb jeder anderen Funktionsaufrufe.
In Ihrem speziellen Fall gibt es sehr wenig, das tatsächlich in der von der Funktion k
erstellten Schließung eingeschlossen ist. Der einzige signifikante Abschluss ist der Verweis auf die Argumente cb
und myId
. Und selbst dann dauert es nur etwa eine Sekunde:
Ich sollte beachten, dass Ihr Code ziemlich verschachtelt ist. Es kann einfacher geschrieben werden und ohne die Verwendung von Closures überhaupt (minus der globalen Variable i), wenn Sie es einfach so schreiben:
%Vor%Diese Zeile ist falsch:
Es erstellt tatsächlich eine Rekursion und nach einer Weile (Woche oder so) - der Prozess wird viel Speicher verbrauchen. (Der Stapel wird nie freigegeben)
Es erstellt nicht Rekursion, weil die Funktion vollständig beendet und dann erneut aufgerufen wird.
Rekursion stapelt sich übereinander
%Vor%Der Stapel sieht so aus
%Vor%Mit setTimeout führen Sie eine Funktion aus. Diese Funktion richtet ein Ereignis ein, damit die Funktion wieder ausgeführt werden kann - aber hier ist der wichtige Unterschied: Die Funktion wird vollständig beendet und ist weg [1]. DANN wird es wieder gerufen.
In der Ausführung unterscheidet es sich nicht viel davon:
%Vor% setTimeout
gibt dem Browser nur die Möglichkeit zu atmen, wenn Sie möchten. Eine Chance für den Bildschirm zu aktualisieren, andere Ereignisse zu verarbeiten. Es ist nicht, um die richtige Terminologie zu verwenden, block
der Browser.
Dies erzeugt kein Speicherleck.
Tatsächlich ist es ein ziemlich allgemein verwendetes Konzept. Normalerweise erscheint es in dieser Form:
%Vor% Wenn Sie häufig (hier alle 10 Millisekunden) nach etwas suchen möchten, kann es besser sein, dieses Muster anstelle von setInterval
zu verwenden, da dies die Seitenleistung verbessern kann. Wenn Ihre Funktion zum Beispiel mehr als 10 Millisekunden benötigt und Sie setInterval(f, 10)
verwenden, wird sie ständig aufgerufen. Wenn Sie jedoch das obige Muster setTimeout
verwenden, stellt es zumindest sicher, dass der Prozessor zwischen jedem Aufruf eine Unterbrechung von 10 Millisekunden erhält, unabhängig davon, wie lange die Ausführung der Funktion dauert.
Siehe dieses Video (ab 7.46 Uhr) von Paul Irish für weitere Informationen über dieses Muster.
>Tags und Links javascript memory-leaks performance