Robert: Funktion periodisch aufrufen mit "SetTimeout"

Hallo,

Wenn ich irgendeine Javascript-Funktion
regelmäßig in bestimmte Zeitabständen
mit setTimeout ausführen möchte, dann
funktioniert das leider nicht so, wie ich's
gerne möchte. Zuerst hab' ich's mit
folgendem Script versucht:

<script language="JavaScript">
<!--
for(var i = 0; i <= 1000; i++)
window.setTimeout("irgendwas()",100);
//-->
</script>

Das Problem ist aber, daß dabei nur eine
einzige (keine wiederholte) Verzögerung
von 100 mS stattfindet. Wie es aussieht
wird so die ganze For-Schleife sofort
1000 mal durchlaufen, und 100 mS später
wird 1000 mal die Funktion aufgerufen.

Daraufhin hab' ich's mit folgender Änderung
probiert:

<script language="JavaScript">
<!--
for(var i = 0; i <= 1000; i++)
window.setTimeout("irgendwas()",100*i);
//-->
</script>

So funktioniert's zwar, aber es gibt andere
Probleme. Ich wollte hinter die For-Schleife
noch einen weiteren Befehl setzen, der erst
nach den 1000 Timeouts ausgeführt werden
sollte, aber er wurde sofort ausgeführt.

Anscheinend finden auch hier die 1000
Schleifen-Durchläufe sofort statt, wobei
der Computer die ganzen Daten für die
1000 planten Funktionsaufrufe sich
anscheinend irgendwie merkt und dann
gleich mit dem Script fortfährt, bevor
die ganzen Funktionsaufrufe stattfinden.

Da denke ich, das könnte den PC schnell
überfordern, wenn man z.B. die Zahl der
Schleifen-Durchläufe noch deutlich erhöht.

Nun meine Fragen:

Gibt es eine Möglichkeit, die den Browser
dazu veranlasst die Timeout-Zeit jeweils
abzuwarten, bevor das Script weiter gelesen
und ausgeführt wird? (Also ähnlich, wie z.B.
bei "alert" das Script ja auch erst weiter
ausgeführt wird, wenn man die Meldung
bestätigt hat.) Eine Art Wait-Befehl gibt
es ja bei JS nicht, aber vielleicht kann man
sowas ja irgendwie simulieren?

Wie ich gesehen habe, macht man das manchmal
über Funktionen, die sich selbst aufrufen, aber
das soll ja auch nicht so optimal sein, da für jeden
weiteren Funktionsaufruf zusätzlicher Speicherplatz
verbraucht wird, und nach meinen Überlegungen
müßten solche Scripte grundsätzlich nach einiger
Zeit abstürzen, denn jeder Funktionsaufruf ist ja
ein kleines Unterprogramm, und so werden dann
ja endlos viele Unterprogramme inneinander
verschachtelt. (Vor allem wenn die Anzahl nicht
wie in meinem Beispiel auf 1000 begrenzt wird.)

Wie sieht nun die korrekte Lösung aus, um eine
Funktion immer wieder periodisch in konstanten
Zeitabständen aufzurufen?

Für Eure Hilfe im Vorraus besten Dank.

Bye,  Robert

  1. Hallo du da draußen,

    ich würds so machen:

    window.setTimeout(irgendwas(), 100);
    function irgendwas()
    {
     for(i=0; i <= 1000; i++)
     {
      // Irgendwas
     }
    }

    Den Rest kannst du vergessen.

    Die Pause erzeugst du z. B. eine For-Schleife, z. B. so:

    for(i = 0; i < 100000000; i++)
    {
     //Irgendwas sinnloses, z. B.
     0 == 0;
    }

    Grüße von hier drinnen, aus Biberach an der Riss,

    <img src="http://mitglied.lycos.de/cdauthunstable/bilder/Grafiken/myname4.png" border=0 alt="">

    1. Hallo du da draußen,

      man muss es natürlich so machen(kleiner Denkfehler):

      var i = 0;
      interval = window.setTimeout("irgendwas()", 100);
      function irgendwas()
      {
       if(i >= 1000)
        window.clearTimeout(interval);
       // http://de.selfhtml.org/javascript/objekte/window.htm#clear_timeout
       else
       {
        // Irgendwas
       }
      }

      Grüße von hier drinnen, aus Biberach an der Riss,

      <img src="http://mitglied.lycos.de/cdauthunstable/bilder/Grafiken/myname5.png" border=0 alt="">

      1. Moin, Dogfish!

        Ich frage mich, wie lange dein Spielchen noch so gehen soll? Probierst du gerade ein Schrifttypenprogramm aus? Oder spielst du mit PhotoShop/Gimp/MS Paint herum?

        Deine Namensgrafiken sehen zwar alle sehr schön aus, werden aber immer größer.

        Kleine Auflistung:
        <img src="http://mitglied.lycos.de/cdauthunstable/bilder/Grafiken/myname.png" border=0 alt="">
        250 x 87 pixels, 19 KB

        <img src="http://mitglied.lycos.de/cdauthunstable/bilder/Grafiken/myname2.png" border=0 alt="">
        336 x 106 pixels, 48 KB

        <img src="http://mitglied.lycos.de/cdauthunstable/bilder/Grafiken/myname3.png" border=0 alt="">
        246 x 96 pixels, 17 KB

        <img src="http://mitglied.lycos.de/cdauthunstable/bilder/Grafiken/myname4.png" border=0 alt="">
        554 x 210 pixels, 67 KB

        <img src="http://mitglied.lycos.de/cdauthunstable/bilder/Grafiken/myname5.png" border=0 alt="">
        540 x 196 pixels, 97 KB

        Noch nicht verwendet wurden:
        <img src="http://mitglied.lycos.de/cdauthunstable/bilder/Grafiken/myname6.png" border=0 alt="">
        554 x 210 pixels, 132 KB

        <img src="http://mitglied.lycos.de/cdauthunstable/bilder/Grafiken/myname7.png" border=0 alt="">
        674 x 330 pixels, 81

        <img src="http://mitglied.lycos.de/cdauthunstable/bilder/Grafiken/myname8.png" border=0 alt="">
        500 x 156 pixels, 69 KB

        <img src="http://mitglied.lycos.de/cdauthunstable/bilder/Grafiken/myname9.png" border=0 alt="">
        500 x 156 pixels, 69 KB

        <img src="http://mitglied.lycos.de/cdauthunstable/bilder/Grafiken/myname10.png" border=0 alt="">
        554 x 210 pixels, 154 KB

        Wunderbar, jetzt haben wir alle Bilder gesehen - du kannst dich dann bitte wieder auf Bilder unter 20 KB beschränken (gerne auch auf Dateigrößen kleiner als 5 KB) - manche Menschen hier im Forum müssen ein Modem benutzen oder Traffic zahlen, und die sind sicherlich nicht begeistert, 150 KB-Banner runterzuladen. Da ist die Toleranzgrenze weit überschritten IMO.

        Ich danke für dein Verständnis.

        - Sven Rautenberg

      2. Hallo,

        man muss es natürlich so machen(kleiner Denkfehler):

        Ich versteh jetzt leider nicht, wie dieses
        Script funktionieren soll, und was die
        clearTimeout-Anweisung bringen soll.

        Ich hab's eben getestet. Das macht nur einen
        einzigen Funktionsaufruf. Da ist doch gar
        keine Schleife oder Wiederholung drin?!?
        (Der Wert i wird auch nirgends verändert.)

        Bye,  Robert

        1. Hi there!

          [quotation rearranged]

          Ich hab's eben getestet. Das macht nur einen
          einzigen Funktionsaufruf. Da ist doch gar
          keine Schleife oder Wiederholung drin?!?
          (Der Wert i wird auch nirgends verändert.)

          Weil da immer noch ein Fehler ist. Er wollte die setInterval()-Funktion statt setTimeout() benutzen.

          Ich versteh jetzt leider nicht, wie dieses
          Script funktionieren soll, und was die
          clearTimeout-Anweisung bringen soll.

          Mit setInterval() ist das clearInterval() ganz doll noetig, sonst wird Deine Funktion bis in alle Ewigkeit immer weiter aufgerufen.

          Ein Alternative waere, am Ende der aufgerufenen Funktion wieder genauso einen setTimout()-Aufruf hinzusetzen, um dafuer zu sorgen, dass die Funktion weitere 100ms spaeter wieder aufgerufen wird. Das ist nicht dasselbe, wie das sofortige rekursive Aufrufen der Funktion, deshalb entsteht da auch kein Problem mit dem Stack, wie Du im ersten Posting vermutet hast.

          So long

          --
          If we do not believe in freedom of speech for people we despise then we don't believe in it at all.
              -- Noam Chomsky

          1. Hallo,

            Weil da immer noch ein Fehler ist.
            Er wollte die setInterval()-Funktion
            statt setTimeout() benutzen.

            Ah ja, Danke für den Hinweis.

            Die setInterval-Funktion kannte ich
            noch nicht. Scheint aber für solche
            Aufgaben das optimale zu sein.

            Bye,  Robert

    2. hallo du da drinnen,

      nur eine Randbemerkung:
      gehts mit der Signaturgrafik (die du zwar in Form und Erscheinungsweise, nicht aber in der Größe in den nachfolgenden postings verändert hast) nicht doch _geringfügig_ kleiner? Eine Signaturgrafik als solche ist durchaus eine gute Idee, aber sie muß nicht derart groß ausfallen ...

      schönste Grüße

      Christoph S.

  2. Hallo.

    <script language="JavaScript">
    <!--
    for(var i = 0; i <= 1000; i++)
    window.setTimeout("irgendwas()",100);
    //-->
    </script>

    Das Problem ist aber, daß dabei nur eine
    einzige (keine wiederholte) Verzögerung
    von 100 mS stattfindet. Wie es aussieht
    wird so die ganze For-Schleife sofort
    1000 mal durchlaufen, und 100 mS später
    wird 1000 mal die Funktion aufgerufen.

    Richtig.

    Daraufhin hab' ich's mit folgender Änderung
    probiert:

    <script language="JavaScript">
    <!--
    for(var i = 0; i <= 1000; i++)
    window.setTimeout("irgendwas()",100*i);
    //-->
    </script>

    So funktioniert's zwar, aber es gibt andere
    Probleme. Ich wollte hinter die For-Schleife
    noch einen weiteren Befehl setzen, der erst
    nach den 1000 Timeouts ausgeführt werden
    sollte, aber er wurde sofort ausgeführt.

    Dann schreib hinter die Schleife doch einfach:
     window.setTimeout("wasandres()",100*i);
    Nach dem Schleifendurchlauf ist i nämlich 1001.

    Anscheinend finden auch hier die 1000
    Schleifen-Durchläufe sofort statt, wobei
    der Computer die ganzen Daten für die
    1000 planten Funktionsaufrufe sich
    anscheinend irgendwie merkt und dann
    gleich mit dem Script fortfährt, bevor
    die ganzen Funktionsaufrufe stattfinden.

    Ja, so sollte das auch sein.

    Da denke ich, das könnte den PC schnell
    überfordern, wenn man z.B. die Zahl der
    Schleifen-Durchläufe noch deutlich erhöht.

    Nö, wieso denn? Im Grunde genommen ist das nichts anderes, als wenn du alle 100ms hingehst und auf nen Knopp drückst, der die Funktion ausührt.

    Nun meine Fragen:

    Gibt es eine Möglichkeit, die den Browser
    dazu veranlasst die Timeout-Zeit jeweils
    abzuwarten, bevor das Script weiter gelesen
    und ausgeführt wird?

    Nein, d.h. nicht ohne ein bissel rumzubasteln.
    Die einfachste Möglichkeit wäre wohl, das, was nach dem Timeout passieren soll, in ne eigene Funktion zu packen und diese ebenfalls mit einem window.setTimeout aufzurufen.

    (Also ähnlich, wie z.B.
    bei "alert" das Script ja auch erst weiter
    ausgeführt wird, wenn man die Meldung
    bestätigt hat.)

    Darauf kann man sich auch nicht verlassen, in Opera z.B. läuft das Script im Hintergrund weiter, auch wenn ein Meldungsfenster erscheint.

    Eine Art Wait-Befehl gibt
    es ja bei JS nicht, aber vielleicht kann man
    sowas ja irgendwie simulieren?

    Wie schon gesagt, alles in Funktionen packen und dann gesondert per window.setTimeout aufrufen:

    <script type="text/javascript">
    <!--
     function part1()
      {
       window.alert("Erster Teil-Abschnitt");
       window.setTimeout("part2()",5000);
       window.alert("Gleich kommt der Zweite.");
      }
     function part2()
      {
       window.alert("Zweiter Teil-Abschnitt");
       window.setTimeout("window.alert('ENDE')",2000);
      }
     part1();
    //-->
    </script>

    Von leeren Schleifen ist aber abzuraten, zum einen unterscheidet sich die Bearbeitungszeit der Browser (vermutlich stark) voneinander und zum andern mag ich Meldungen wie "Ein Skript auf dieser Seite verursacht eine Verzögerung..." nicht wirklich.

    Wie ich gesehen habe, macht man das manchmal
    über Funktionen, die sich selbst aufrufen, aber
    das soll ja auch nicht so optimal sein, da für jeden
    weiteren Funktionsaufruf zusätzlicher Speicherplatz
    verbraucht wird, und nach meinen Überlegungen
    müßten solche Scripte grundsätzlich nach einiger
    Zeit abstürzen, denn jeder Funktionsaufruf ist ja
    ein kleines Unterprogramm, und so werden dann
    ja endlos viele Unterprogramme inneinander
    verschachtelt. (Vor allem wenn die Anzahl nicht
    wie in meinem Beispiel auf 1000 begrenzt wird.)

    Alles richtig, so liefert z.B.
    <script type="text/javascript">
    <!--
     function foo()
      {
       foo();
      }
     foo();
    //-->
    </script>
    einen "stack overflow", bzw. "out of memory at line...", bzw. "too much recursion", o.ä.
    Um sowas zu verhindern kann man dann window.setTimeout verwenden:
    <script type="text/javascript">
    <!--
     function foo()
      {
       window.setTimeout("foo()",0);
      }
     foo();
    //-->
    </script>
    Das Script wird dann nicht mehr von sich selbst aufgerufen, sondern vom Timeout.

    Wie sieht nun die korrekte Lösung aus, um eine
    Funktion immer wieder periodisch in konstanten
    Zeitabständen aufzurufen?

    Entweder mit window.setTimeout:

    <script type="text/javascript">
    <!--
     function foo()
      {
       document.bgColor = (document.bgColor == "#ffffff") ? "#000000" : "#ffffff"; // Was für's Auge
       window.setTimeout("foo()",500);
      }
     foo();
    //-->
    </script>

    Wobei die Funktion hier sofort gestartet wird, oder mit window.setInterval:

    <script type="text/javascript">
    <!--
     function foo()
      {
       document.bgColor = (document.bgColor == "#ffffff") ? "#000000" : "#ffffff";
      }
     window.setInterval("foo()",500);
    //-->
    </script>

    Hier wird erst 500ms gewartet, und dann startet der erste Funktionsaufruf.

    Gruß
    Norbert

  3. Hallo,

    richtig ist, "irgendwas nur einmal aufzurufen, und am Ende per und nicht gleich 100 Aufrufe in dem browser zu setzen.
    abbrechen kannst du jederzeit, z.B. durch Mitzählen einer globalen Variablen oder per Mausclick usw.

    Also:

    <script language="JavaScript">
    <!--

    var Zaehler=0
    function Schleife() {
       //
       // jetz mach mal was
       //
       Zaehler++
       if (Zaehler==1000) { // nu mach was anders }

    if (Zaehler <1000) {
          window.setTimeout("Schleife()",100)
       }
    }

    //-->
    </script>

    ... onLoad=Schleife() ...

    Gruß
    Hans35