Maurice: setInterval

Hallo Leute,

ich hätte mal ne kleine Frage zu den Intervallen.

Ist es möglich einen Intervall mehrere male aufzurufen ohne das es zu Komplikationen kommt. Ich finde leider keinen Weg wie ich das korrekt umsetzen kann :(

Als Beispiel... Wie bekomme ich das korrekt in gang?

  
function start(endlaenge) {  
   *code wird bearbeitet*  
   laenge = laenge + 1;  
   if(laenge >= endlaenge) {  
       window.clearInterval(interval);  
       }  
   }  
  
function {  
   var laenge = 0;  
   interval = window.setInterval(function() { start(100); }, 50);  
   var laenge = 0;  
   interval = window.setInterval(function() { start(500); }, 50);  
   }  

Wie erreiche ich das beide (oder mehr) fehlerfrei bis zum ende laufen?

Vielen Dank schonmal

  1. Hakuna matata!

    Wie erreiche ich das beide (oder mehr) fehlerfrei bis zum ende laufen?

    setInterval() gibt eine Nummer zurück, mit der das Intervall identifiziert werden kann. Diese Nummer kann man später clearInterval() als Parameter übergeben, damit clearInterval weiß, welches Intervall es löschen soll. Du speicherst die IDs deiner beiden Intervalle allerdings in der selben Variablen, so überschreibst du also beim Start des zweiten Intervalls die Nummer des ersten Intervalls. Du müsstest diese Nummern getrennt voneinander speichern, zum Beispiel in mehreren Variablen oder in einem Array. Ganz ähnlich ist es mit deiner laenge-Variable. Beide Intervalle sollten eigentlich getrennte Zählvariablen benutzen, und nur ihre eigenen Aufrufe zählen. Du benutzt aber die selbe globale Variable für beide Intervalle.

    --
    “All right, then, I'll go to hell.” – Huck Finn
    1. Aloha ;)

      Du benutzt aber die selbe globale Variable für beide Intervalle.

      GLOBALE Variable? Soll heißen function { var foo = bar; } wirkt wie { var foo = bar; } bzw. wie var foo = bar; oder wie? Wäre mir neu (nicht, dass es deshalb Nicht sein kann :D)

      Bitte um Bestätigung.

      Grüße,

      RIDER

      --
      Camping_RIDER a.k.a. Riders Flame a.k.a. Janosch Zoller
      ch:? rl:| br:> n4:? ie:% mo:| va:) js:) de:> zu:) fl:( ss:| ls:[
      1. Hakuna matata!

        Du benutzt aber die selbe globale Variable für beide Intervalle.

        GLOBALE Variable? Soll heißen function { var foo = bar; } wirkt wie { var foo = bar; } bzw. wie var foo = bar; oder wie?

        Nein, da hast du mich missverstanden. Ich sprach von der start-Funktion. Die Variable laenge wird hier nicht mit dem var-Schlüsselwort deklariert und ist auch kein Parameter und wird deshalb automatisch in allen übergeordneten Gültigkeitsbereichen bis hin zum globalen Scope gesucht:

        globales bar:

        function foo () {  
           bar = 'whoop';  
        }  
        foo();  
        console.log( bar ); // whoop
        

        lokales bar:

        function foo () {  
           var bar = 'whoop';  
        }  
        foo();  
        console.log( bar ); // Uncaught Reference Error: bar is not defined
        

        In der unbenannten Funktion wird laenge zwar lokal daklariert, aber wie du bereits in deiner anderen Antwort richtig erklärt hast, kann die start-Funktion nicht auf diesen Gültigkeitsbereich zugreifen. Wir wollten beide auf das gleiche hinaus, nur aus unterschiedlichen Perspektiven.

        --
        “All right, then, I'll go to hell.” – Huck Finn
  2. Aloha ;)

    function start(endlaenge) {
       code wird bearbeitet
       laenge = laenge + 1;
       if(laenge >= endlaenge) {
           window.clearInterval(interval);
           }
       }

    function {
       var laenge = 0;
       interval = window.setInterval(function() { start(100); }, 50);
       var laenge = 0;
       interval = window.setInterval(function() { start(500); }, 50);
       }

      
    Du scheinst hier grundsätzlich etwas falsch verstanden zu haben. In deiner Intervallfunktion start willst du auf laenge zugreifen, das in der zweiten Funktion (warum hat diese eigentlich keinen Namen oder Parameterklammern? Wahrscheinlich ein Tippfehler) als laenge = 0 definiert wurde. Das kann so nicht funktionieren. laenge = 0 ist im Scope der zweiten Funktion, die Funktion start 'kennt' diese nicht. Dir wird auch auffallen, dass die Variable interval aus dem selben Grund gar nicht definiert ist. Du musst also insgesamt was am Funktionsdesign ändern.  
      
    Möglichkeit 1: globale Variablen  
      
    ~~~javascript
      
    function start(endlaenge,index) {  
       *code wird bearbeitet*  
       laengen[index] = laengen[index] + 1;  
       if(laengen[index] >= endlaenge) {  
           window.clearInterval(intervals[index]);  
           }  
       }  
      
    var laengen = [];  
    var intervals = [];  
      
    function blabla() {  
       laengen[laengen.length] = 0;  
       intervals[laengen.length-1] = window.setInterval(function() { start(100,laengen.length-1); }, 50);  
       laengen[laengen.length] = 0;  
       intervals[laengen.length-1] = window.setInterval(function() { start(500,laengen.length-1); }, 50);  
       }  
      
    blabla();  
    
    

    Möglichkeit 2: setTimeout - würde ich deutlich bevorzugen

      
    function start(laenge,endlaenge,step) {  
       *code wird bearbeitet*  
       laenge = laenge + 1;  
       if(laenge < endlaenge) {  
           window.setTimeout(function() { start(laenge,endlaenge,step); },step);  
       }  
      
    function blabla() {  
       window.setTimeout(function() { start(0,100,50); }, 50);  
       window.setTimeout(function() { start(0,500,50); }, 50);  
       }  
      
    blabla();  
    
    

    Noch ein paar Worte zu Argumenten innerhalb anonymer Funktionen in window.setTimeout...

    Hier habe ich das so gelöst:

    window.setTimeout(function() { start(laenge,endlaenge,step); },step);

    Das ist dann problematisch, wenn laenge, endlaenge oder step nach Aufruf von setTimeout geändert würden. Hier werden nämlich die aktuellsten Werte übergeben. Es gibt zwei andere, teils nicht weniger problematische Möglichkeiten.

    window.setTimeout("start("+laenge+","+endlaenge+","+step+")",step);

    Da du nur Zahlen übergibst, ist auch das eine Möglichkeit, die die o.g. Nachteile nicht hat. Du solltest dann aber vor jedem Aufruf prüfen, ob laenge, endlaenge und step tatsächlich Zahlen sind. Ansonsten besteht die potenzielle Gefahr einer Code-Injection. (Die aber auch vernachlässigbar wäre, da JavaScript per Konsole sowieso jederzeit ausführbar ist). Der tatsächliche Problemfaktor ist hier die Performance, da die per String übergebene Funktion intern zunächst mit eval ausgewertet werden muss.

    window.setTimeout(start,step,laenge,endlaenge,step);

    Das ist bei weitem die beste (und modernste) Möglichkeit. Ohne bisher genannte Nachteile. Jetzt kommt das große Aber: es funktioniert im IE erst ab Version 10. Da IE 10 für Vista leider nicht verfügbar ist, werden wir damit wohl warten müssen, bis Microsoft den Support für Vista einstellt.

    Grüße,

    RIDER

    --
    Camping_RIDER a.k.a. Riders Flame a.k.a. Janosch Zoller
    ch:? rl:| br:> n4:? ie:% mo:| va:) js:) de:> zu:) fl:( ss:| ls:[
    1. Aloha ;)

      Du scheinst hier grundsätzlich etwas falsch verstanden zu haben. In deiner Intervallfunktion start willst du auf laenge zugreifen, das in der zweiten Funktion (warum hat diese eigentlich keinen Namen oder Parameterklammern? Wahrscheinlich ein Tippfehler) als laenge = 0 definiert wurde. Das kann so nicht funktionieren. laenge = 0 ist im Scope der zweiten Funktion, die Funktion start 'kennt' diese nicht. Dir wird auch auffallen, dass die Variable interval aus dem selben Grund gar nicht definiert ist. Du musst also insgesamt was am Funktionsdesign ändern.

      Ups, blame me. Meine Begründung war natürlich falsch. Ich habe closures vergessen... start hat also schon Zugriff auf die Variablen. Tatsächlich ist 1UnitedPowers Erklärung die Richtige, meine Lösungsansätze funktionieren aber trotzdem.

      Grüße,

      RIDER

      --
      Camping_RIDER a.k.a. Riders Flame a.k.a. Janosch Zoller
      ch:? rl:| br:> n4:? ie:% mo:| va:) js:) de:> zu:) fl:( ss:| ls:[
      1. Aloha ;)

        Aloha ;)

        Du scheinst hier grundsätzlich etwas falsch verstanden zu haben. In deiner Intervallfunktion start willst du auf laenge zugreifen, das in der zweiten Funktion (warum hat diese eigentlich keinen Namen oder Parameterklammern? Wahrscheinlich ein Tippfehler) als laenge = 0 definiert wurde. Das kann so nicht funktionieren. laenge = 0 ist im Scope der zweiten Funktion, die Funktion start 'kennt' diese nicht. Dir wird auch auffallen, dass die Variable interval aus dem selben Grund gar nicht definiert ist. Du musst also insgesamt was am Funktionsdesign ändern.

        Ups, blame me. Meine Begründung war natürlich falsch. Ich habe closures vergessen... start hat also schon Zugriff auf die Variablen. Tatsächlich ist 1UnitedPowers Erklärung die Richtige, meine Lösungsansätze funktionieren aber trotzdem.

        Ah, meine ursprüngliche Begründung stimmte also doch. Klar. Denn damit start auf die lokal definierten Variablen der 2. Funktion zugreifen könnte, müsste start innerhalb der zweiten Funktion definiert worden sein, tatsächlich steht innerhalb der zweiten Funktion aber nur der Aufruf von start. Dementi dementiert :P mistiger closures-Brainfuck ;)

        Grüße,

        RIDER

        --
        Camping_RIDER a.k.a. Riders Flame a.k.a. Janosch Zoller
        ch:? rl:| br:> n4:? ie:% mo:| va:) js:) de:> zu:) fl:( ss:| ls:[
    2. Oh man ja... an eine Verwendung eines Array habe ich nicht gedacht, es kann doch so einfach sein ;D

      Hehe das hat jetzt ja eine heiße Diskussion ausgelöst mit der zweiten Funktion :D Das ist nur ein Flüchtigkeitsfehler, die Gültigkeiten von Variablen und Funktionen sind mir bewusst tut mir leid mein Fehler...

      Aber warum würdest du mir setTimeout empfehlen? Es mag einfacher sein aber von der Performance her ist das doch recht arbeitsintensiv oder nicht?

      1. Aloha ;)

        Aber warum würdest du mir setTimeout empfehlen? Es mag einfacher sein aber von der Performance her ist das doch recht arbeitsintensiv oder nicht?

        Einfach deshalb, weil man damit um das elendige clearen des Interval und damit um die Speicherung des Interval-Handle drumrumkommt. Ganz zu schweigen vom index-Parameter. Du siehst auch, dass du im Gegensatz zur setInterval-Methode bei der setTimeout-Methode um das Setzen globaler Counter-Variablen herumkommst (und ein Setzen globaler Variablen sollte imho immer bedeutungsvoll und mit Bedacht und nicht wie hier "einfach so" geschehen). Dadurch kann jeder durch setTimeout angeleierte Prozess als in sich abgeschlossene Sache betrachtet werden, du musst nie die Angst haben, dass der mit anderen interferiert.

        Grundsätzlich ist ein setTimeout imho nicht arbeitsintensiver als ein setInterval, mich würde es wundern, wenn setInterval intern irgendetwas anderes wäre als die Mechanik, die auch bei setTimeout zum Zuge kommt - nur, dass bei setInterval unendlich viele Timeouts (bzw. deren interne Repräsentation) aneinandergereiht werden. Wenn, dann unterscheidet sich das ganze darin, dass bei setTimeout bei jedem step eine neue anonyme Funktion (innerhalb des setTimeout) definiert wird, während setInterval wahrscheinlich jedesmal die selbe anonyme Funktion abarbeitet, der dadurch entstehende overhead ist aber wirklich vernachlässigbar.

        Für mich - aber das ist wirklich nur persönliche Vorliebe - ist es so, dass ich mit setInterval nur diejenigen Dinge realisiere, die tatsächlich unendlich oft wiederholt werden sollen. Dabei handelt es sich dann auch um Dinge, die tatsächlich vom einen zum anderen Schritt nicht direkt aufeinander aufbauen (z.B. das wiederholte Refreshen eines bestimmten Content etc.); für alle Dinge, die endlich ablaufen, und insbesondere für aufeinander aufbauende Schritte (wie du es hier gegeben hast), benutze ich lieber von vornherein setTimeout und baue meine Funktion dann so, dass sie alle wichtigen Infos per Parameter an den nächsten Schritt weitergeben kann (wie in meinem Codebeispiel).

        Grüße,

        RIDER

        --
        Camping_RIDER a.k.a. Riders Flame a.k.a. Janosch Zoller
        ch:? rl:| br:> n4:? ie:% mo:| va:) js:) de:> zu:) fl:( ss:| ls:[
        1. Ok vielen dank für die ausführliche Antwort. Die Sache hat mir wirklich sehr weiter geholfen :)

          Eine kleine letzte Frage hätte ich jedoch noch ;) ist es möglich einen Verweis in einer Variable zu speichern?

          also...

          variable = document.getElementById(id).style.height;

          um sie dann später in kurzschrift zu verwenden

          variable = 100px;

          ein:
          variable = document.getElementById();
          funktioniert ja, jedoch wird bei genauerer Angabe ja der Wert gespeichert.

          1. Aloha ;)

            Eine kleine letzte Frage hätte ich jedoch noch ;) ist es möglich einen Verweis in einer Variable zu speichern?

            also...

            variable = document.getElementById(id).style.height;

            um sie dann später in kurzschrift zu verwenden

            variable = 100px;

            Du suchst nach einer Möglichkeit, in JavaScript Referenzen statt Werten in Variablen zu speichern.

            Grundsätzlich verhält sich JavaScript so:

            Wenn eine Variable mit einem Objekt (auch Arrays sind übrigens Objekte) belegt wird, wird eine Referenz gespeichert.

            variable = document.getElementById(id).style;  
            variable.height = 100px;  
            alert(document.getElementById(id).style.height); \\ 100px  
            
            

            Wenn eine Variable mit einem simplen Datentyp belegt wird, wird nur der Wert gespeichert.

            variable = document.getElementById(id).style.height;  
            variable = 100px;  
            alert(document.getElementById(id).style.height); \\ nicht 100px, aber Leerstring oder defaultwert  
            
            

            Simple Datentypen in diesem Sinne sind Zahlen, Strings und booleans.

            Man kann grundsätzlich, wenn das gewünscht ist, simple Datentypen in Objekten wrappen, um das gewünschte Verhalten zu erreichen (in deinem Fall ist das nicht hilfreich). Etwa so:

            // declare an object with property x  
            var obj = { x: 1 };  
            var anotherObj = obj;  
            anotherObj.x++;  
            alert(obj.x); // displays 2
            

            (nicht auf meinem eigenen Mist gewachsen, [Quelle])

            In deinem Fall würde es sich aber dann anbieten, einfach wie in meinem ersten Beispiel das übergeordnete Objekt abzuspeichern. Wenn es ganz schnell gehen soll, kann das ganze dann noch so abgekürzt werden:

            v = document.getElementById(id).style;  
            h = 'height';  
            v[h] = 100px;  
            alert(document.getElementById(id).style.height); \\ 100px  
            
            

            Eine Möglichkeit, JavaScript zu zwingen, Referenzen abzuspeichern (wie in PHP mit dem =&-Operator) gibt es imho nicht.

            Grüße,

            RIDER

            --
            Camping_RIDER a.k.a. Riders Flame a.k.a. Janosch Zoller
            ch:? rl:| br:> n4:? ie:% mo:| va:) js:) de:> zu:) fl:( ss:| ls:[
            1. Aloha ;)

              @Edit:

              Eine Möglichkeit, JavaScript zu zwingen, Referenzen abzuspeichern (wie in PHP mit dem =&-Operator) gibt es imho nicht.

              Ich hatte noch kurz die Idee, die primitiven Datentypen String und Number durch ihre Objektrepräsentation darzustellen und so statt mit primitiven Datentypen mit String-Objekten / Number-Objekten zu arbeiten.

              (also in etwa so: s = new String('100px'); document.getElementById("test").style.height = s;)

              Das scheitert aber zuerst einmal daran, dass es keine Methode gibt, bestehende String- oder Number-Objekte zu verändern (man könnte höchstens in s einen neuen String abspeichern, dann würde man aber lediglich die in s gespeicherte Referenz ändern) und zweitens scheitert es daran, dass beim Übertragen von Objekten aus String/Number wohl wieder nur die primitiven Datentypen weitergereicht werden:

              s = new String('100px');  
                
              document.getElementById("test").style.height = s;  
                
              alert(typeof s); //object  
              alert(typeof document.getElementById("test").style.height); //string
              

              Grüße,

              RIDER

              --
              Camping_RIDER a.k.a. Riders Flame a.k.a. Janosch Zoller
              ch:? rl:| br:> n4:? ie:% mo:| va:) js:) de:> zu:) fl:( ss:| ls:[
              1. Super. Vielen Dank an euch.

                Tut mir leid wegen der Fehler, ich war immer auf dem Sprung wenn ich das geschrieben hatte und war wohl etwas schlampig...

                Dank euch konnte ich meinen Code auf jeden Fall um 2/3 verkürzen :-)

            2. Aloha ;)

              Und ja, Martin, ich habs schon wieder verbockt und meine einzeiligen Kommentare statt mit // mit \ eingeleitet. Blöde Angelegenheit -.-

              Bitte nicht wieder hauen^^

              Grüße,

              RIDER

              --
              Camping_RIDER a.k.a. Riders Flame a.k.a. Janosch Zoller
              ch:? rl:| br:> n4:? ie:% mo:| va:) js:) de:> zu:) fl:( ss:| ls:[
              1. Hallo,

                Und ja, Martin, ich habs schon wieder verbockt und meine einzeiligen Kommentare statt mit // mit \ eingeleitet. Blöde Angelegenheit -.-

                stimmt, wäre mir diesmal gar nicht aufgefallen.
                Aufgefallen ist mir aber, dass du der Code-Vorlage von Maurice auf den Leim gegangen bist nicht nicht gemerkt hast, dass

                height = 100px;

                ein Syntaxfehler ist.

                Fröhliche Weihnachten,
                 Martin

                --
                Finanztipp:
                Leihen Sie sich Geld von einem Pessimisten.
                Er rechnet sowieso nicht damit, dass er es zurückbekommt.
                Selfcode: fo:) ch:{ rl:| br:< n4:( ie:| mo:| va:) de:] zu:) fl:{ ss:) ls:µ js:(
                1. Aloha ;)

                  Oops, Asche über mein Haupt... Hätte ich doch besser den Quelltext aus meinem kleinen JSFiddle-Test genommen, anstatt die Steilvorlage zu nutzen :P

                  Grüße,

                  RIDER

                  --
                  Camping_RIDER a.k.a. Riders Flame a.k.a. Janosch Zoller
                  ch:? rl:| br:> n4:? ie:% mo:| va:) js:) de:> zu:) fl:( ss:| ls:[