Infinite Timer-Schleife mit javascript ( kein setInterval)?
Wurde ich gefragt (von einem Freund) zu bauen, einen timer (unendliche eine, die schreibt eine Zeile pro Sekunde), aber ohne setInterval
.
Ich gelöst es mit :
var i = 0;
function k(myId, cb)
{
setTimeout(function ()
{
console.log(myId);
cb();
}, 1000);
}
function go()
{
i++;
k(i, go);
}
go();
Und es funktioniert.
Das problem ist, dass ich fürchte, es wird ein memory-Druck. Es entsteht tatsächlich eine Rekursion und nach einer Weile (Woche oder so) - der Prozess verbraucht viel Speicher. (stack ist nie freigegeben)
Wie kann ich das ändern mein code, um nicht zu viel Speicher verbrauchen?
- "Ich fürchte, es wird ein memory Druck" - Sie sind besorgt, dass es sein könnte, oder Sie haben es getestet und es ist? Sie erwähnen es läuft für eine Woche, hast du eigentlich tun, und haben ein problem? Wie bereits in den Antworten unter dieser nicht zu einer Rekursion. Auch, warum die triple-Funktion setup mit
go()
undk()
und die anonym-Funktion? Sie konnten denconsole.log()
innerhalbgo()
tun, und dannsetTimeout(go,1000)
.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Es ist nicht die Rekursion
Kann es wie eine Rekursion, aber setTimeout erstellt keine Rekursion.
Den Weg setTimeout funktioniert, ist, dass es sofort zurückgegeben. Also der Aufruf an
k
endet sofort mit seinem stack freigegeben.Wenn das timeout ist eigentlich passiert, und der Aufruf von
go
wieder passiert, es ist nicht aus der Sicht des vorherigen Aufrufk
aber aus dem globalen scope*.* Anmerkung: ich bin nicht mit der strengen Bedeutung Umfang wie definiert in ECMAScript-Spezifikationen hier. Was ich meine ist der Aufruf
k
gemacht werden, als ob Sie haben es geschrieben in einem einfachen<script></script>
- tag: das ist zu sagen, außerhalb jeder anderen Funktion Aufrufe.In Bezug auf Ihre Besorgnis über die Schließung
In Ihrem speziellen Fall, gibt es sehr wenig, was ist eigentlich in der geschlossenen Verschluss erstellt durch die
k
Funktion. Der einzige signifikante Schließung ist die Bezugnahme auf die Argumentecb
undmyId
. Und selbst dann-es dauert nur für etwa eine Sekunde:Könnte einfacher sein
Sollte ich beachten Sie, dass Ihr code ist ziemlich verschachtelt ist. Es kann geschrieben werden, einfacher, und ohne Verwendung von Verschlüssen an alle (abzüglich der globalen variable i), wenn Sie einfach schreiben es so:
go
wieder passiert, es beginnt mit einer neuen leeren stack. Es geht nicht weiter, um zu den vorherigen Stapel."k
? Die anonyme Funktion übergebensetTimeout()
verwendet, um die Parameter vonk()
so, obwohlk()
abgeschlossen hat, ausführen Stücke noch hängen, um zumindest für eine Weile...Diese Zeile ist falsch:
Tut es nicht erstellen einer Rekursion, da die Funktion beendet komplett und wird dann erneut aufgerufen.
Rekursion-Stapel auf der jeweils anderen
Dem Stapel sieht wie folgt aus
Mit setTimeout Sie eine Funktion ausführen. Diese Funktion stellt ein Ereignis für die Funktion wieder zu laufen -- aber hier ist der wichtige Unterschied: Die Funktion beendet wird, vollständig, und ist gegangen[1]. DANN heißt es wieder.
Ausführung weisen ist es nicht viel anders aus, dies zu tun:
setTimeout
nur gibt der browser eine chance zu "atmen", wenn man so will. Eine chance für den Bildschirm zu aktualisieren, andere Ereignisse zu verarbeiten. Es nicht, den Gebrauch der richtigen Terminologieblock
browser.setTimeout
Aufruf erzeugt eine Schließung der äußeren Funktion Ausführungskontext und explizit zucb
, so gibt es eine Umfang-Stapel gebildet. Es kann optimiert werden, Weg, da die nur gebraucht, Verschluss ist auf die unmittelbaren äußeren und globalen zusammenhängen, aber das ist von der Implementierung abhängig und vielleicht nicht zuverlässig. In jedem Fall hast du Recht, das sollte es nicht schaffen, alle Probleme.a();a();a()
BeispielsetTimeout
die äußerenk
Funktion und das Globale Objekt. Aber wenn die anonyme Funktion aufgerufen wird, und beendet die Ausführung, es ist (oder sein sollte) für die Speicherbereinigung zur Verfügung. Ein neuer Verschluss ist gebildet mit der neuen Funktion der neuensetTimeout
, aber es nicht mit der vorherigen Schließung, es ist ein völlig neuer Kontext für die Ausführung.Bedeutet dies nicht, erstellen Sie eine Speicher-Leck.
In der Tat, es ist eine ziemlich Häufig verwendete Konzept. In der Regel erscheint in dieser form:
Wenn Sie überprüfen wollen, für etwas, was oft (hier alle 10 Millisekunden), kann es besser sein, auf dieses Muster statt
setInterval
denn es kann verbessern Sie Ihre Seite Leistung. Zum Beispiel, wenn Ihre Funktion dauert mehr als 10 Millisekunden ausgeführt, und Sie verwendensetInterval(f, 10)
dann wird es immer aufgerufen wird. Jedoch, wenn Sie diesetTimeout
Muster oben, es wird zumindest machen Sie sicher, dass der Prozessor bekommt einen 10 Millisekunden Pause zwischen jeder Anruf, egal wie lange Ihre Veranstaltung dauert, um Sie auszuführen.Sehen in diesem video (ab 7:46) von Paul Irish für mehr Informationen über dieses Muster.