Zombiejesus: window.setTimeOut

Hallo,

kann es sein, das wenn man diese Funktion aufruft, eine Art neuer Thread/Process geöffnet wird und mehrere Sachen Parallel ablaufen? Hier das Grundprinzip meiner Seite (kann meine Quellcode wegen Plagiatfinder nicht veröffentlichen):

  
function main() // wird als onclick verwendet  
{  
      sup();  
      alert("stelle1");  
}  
function sup()  
{  
     alert("stelle 2");  
     ...  
     ...weiterer Quellcode...  
     ...  
     windows.setTimeOut(function() { sup()},1);  
}  

hierbei wird mir in dem Allert-Fenster diese Reihenfolge angezeigt:
stelle2
stelle1
stelle2
stelle2
stelle2
...

Ich möchte aber himbekommen, dass er so vorgeht:
stelle2
stelle2
stelle2
...
stelle1

So das Problem hierbei ist aber, dass wenn ich setTimeOut nicht benutze, werden mir die einzelnen durchläufe von sup() nicht angezeigt, sonder nur das Endprodukt. Wie kann ich es also hinbekommen, dass bei jedem durchlauf das Ergebnis auf der Seite angezeigt wird von Sup() und es dannach erst in main() weitergeht.

  1. Hallo,

    windows.setTimeOut(function() { sup()},1);

    eine Millisekunde scheint etwas plötzlich ;-)

  2. Hallo,

    über setTimeout aufgerufene Befehle werden nach der gewünschten Zeit in die "Befehlsschlange" gesetzt und dann abgearbeitet, wenn Sie dran sind. Daher hat der Browser auch Zeit, Änderungen anzuzeigen.

    Ich möchte aber himbekommen, dass er so vorgeht:
    stelle2
    stelle2
    stelle2
    ...
    stelle1

    Wie kann ich es also hinbekommen, dass bei jedem durchlauf das Ergebnis auf der Seite angezeigt wird von Sup() und es dannach erst in main() weitergeht.

    gar nicht. setTimeout nimmt die Befehle aus dem normalen Programmfluss. Das kannst du nur über die Programmlogig lösen:

    main -> Stelle2
    Stelle 2 -> Bedingung? Stelle2 oder Stelle1
    Stelle1 -> ...

    Gruß, Jürgen

  3. Hallo,

    kann es sein, das wenn man diese Funktion aufruft, eine Art neuer Thread/Process geöffnet wird und mehrere Sachen Parallel ablaufen?

    In JavaScript gibt es nur einen Thread und nichts wird wirklich parallel ausgeführt (Web Worker einmal ausgenommen). Man spricht von einem Event-Loop. Im Grunde ist das eine Warteschlange, die anstehende Funktionsaufrufe strikt nacheinander abarbeitet.

    Mit setTimeout sorgt man dafür, dass die angegebene Funktion am Ende dieser Warteschlange eingefügt wird. Es wird erst der aktuelle Funktionsstapel abgearbeitet, dann mit der angegebenen Verzögerung die neue Funktion ausgeführt.

    hierbei wird mir in dem Allert-Fenster diese Reihenfolge angezeigt:
    stelle2
    stelle1
    stelle2
    stelle2
    stelle2

    Das ist völlig logisch, ja. setTimeout sorgt dafür, dass »sup« wieder ausgeführt wird, nachdem »main« vollständig abgearbeitet ist.

    So das Problem hierbei ist aber, dass wenn ich setTimeOut nicht benutze, werden mir die einzelnen durchläufe von sup() nicht angezeigt, sonder nur das Endprodukt.

    Wahrscheinlich macht dein JavaScript DOM-Änderungen oder sonstige rechenintensive synchrone Dinge.

    Solange ein JavaScript läuft, ist der Browser geblockt und rendert die Seite nicht neu. Änderungen am DOM werden i.d.R. erst sichtbar, wenn das JavaScript zum Stillstand gekommen ist. Wenn du 1000 Elemente erzeugst und nacheinander ohne Unterbrechung ins DOM einhängst, so sieht der Nutzer nicht eins nachdem anderen auftauchen, sondern sieht lange nichts und dann 1000 auf einen Schlag.

    Wie kann ich es also hinbekommen, dass bei jedem durchlauf das Ergebnis auf der Seite angezeigt wird von Sup() und es dannach erst in main() weitergeht.

    Letztlich ist die Lösung, asynchron und schrittweise zu arbeiten und dem Browser Zeit zu geben, zwischendrin die Seite zu rendern. setTimeout mit einem entsprechend hohem Verzögerungswert ist eine Möglichkeit, ausdrücklicher ist requestAnimationFrame. Das weist den Browser an, das Dokument auf den Bildschirm zu zeichnen, und dann asynchron mit dem nächsten Schritt weiterzumachen.

    Vermutlich brauchst du eine Schleife, die eine bestimmte Operation wiederholt. Allerdings keine synchrone for- oder while-Schleife, sondern ein wiederholtes Aufrufen einer Schrittfunktion mit setTimeout/requestAnimationFrame, bis das Ende erreicht ist. Beispiel mit 100 Durchläufen (ungetestet, es geht ums Prinzip):

    var i = 0, max = 100;  
    var step = function () {};  
    var loop = function () {  
      if (i < max) {  
        step();  
        requestAnimationFrame(loop);  
        i++;  
      } else {  
        end();  
      }  
    };  
    var end = function () {};
    

    Hier wird die step-Funktion 100 mal aufgerufen, dazwischen wird mit requestAnimationFrame immer ein Rendering ausgelöst. Die loop-Funktion ruft sich immer wieder selbst auf mit requestAnimationFrame, bis 100 Durchläufe erreicht sind.

    Siehe auch diesen Thread:
    http://forum.de.selfhtml.org/archiv/2013/6/t214005/
    Und mein Beispiel dort:
    http://jsfiddle.net/molily/BfAVX/

    Grüße,
    Mathias

    1. Hallo molily,

      requestAnimationFrame.

      wie ist denn inzwischen die Browserunterstützung? Bisher habe ich lieber setTimeout genommen - sicher ist sicher ...

      Gruß, Jürgen

      1. requestAnimationFrame.

        wie ist denn inzwischen die Browserunterstützung?

        Alle neueren Browser kennen es: http://caniuse.com/requestanimationframe

        Bisher habe ich lieber setTimeout genommen - sicher ist sicher ...

        Der erstgenannte Link beinhaltet einen Polyfill, sodass setTimeout als Fallback verwendet wird, wenn requestAnimationFrame nicht verfügbar ist. Diesen Polyfill sollte man auf jeden Fall einsetzen.

        Mathias

      2. Hallo Jürgen,

        requestAnimationFrame.

        wie ist denn inzwischen die Browserunterstützung? Bisher habe ich lieber setTimeout genommen - sicher ist sicher ...

        guckst du http://caniuse.com/#search=requestAnimationFrame

        Insbesondere die noch "mangelhafte" Unterstützung im Bereich der Mobile Devices dürfte etwas problematisch sein. Und auch wenn man die IEs betrachtet, ist der reine Support des IE 10 vermutlich auch nicht ausreichend (für viele).

        Der Vorteil bei Javascript-Geschichten ist aber ja, dass man erstens den nativen Support checken kann, und falls nicht vorhanden, über entsprechende Funktionen (Polyfills/ Shims) die Funktionalität "nachbauen" kann.

        Siehe bspw.: http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/ (und den darin enthaltenen Link zu dem Polyfill)

        Gruß Gunther

        1. Tja, da war Mathias mal wieder schneller ...!
          Es beruhigt mich aber, dass wir inhaltlich übereinstimmen. :-)

          Schönen Sonntag noch!

          Gruß Gunther

        2. requestAnimationFrame

          Siehe bspw.: http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/

          Wozu setze ich eigentlich Links, wenn sie niemand aufruft? ;)

          Mathias

          1. Wozu setze ich eigentlich Links, wenn sie niemand aufruft? ;)

            Das musst du nicht mich fragen, sondern Jürgen! :-P
            Wobei ich zugeben muss, dass ich ihm auch nicht gefolgt bin ...! ;-)

            Gruß Gunther

            1. Hallo Gunther, hallo Mathias,

              Wozu setze ich eigentlich Links, wenn sie niemand aufruft? ;)

              Das musst du nicht mich fragen, sondern Jürgen! :-P

              ich habe den Link natürlich gelesen, ich bin nur nicht auf die Idee gekommen, bei caniuse nachzusehen.

              Würde denn

              if(!window.requestAnimationFrame)  
                window.requestAnimationFrame = function(callback) { window.setTimeout(callback,1) };
              

              als Minimal-Polyfill reichen? Es geht nur um den Ersatz von setTimeout.

              Gruß, Jürgen

              1. Würde denn

                if(!window.requestAnimationFrame)

                window.requestAnimationFrame = function(callback) { window.setTimeout(callback,1) };

                
                >   
                > als Minimal-Polyfill reichen?  
                  
                Viele Browser [unterstützen](http://caniuse.com/requestanimationframe) requestAnimationFrame mit Vendor-Prefix, daher sind die Polyfills, die das berücksichtigen, schon sinnvoller.  
                  
                Mathias
                
                -- 
                [9elements – Ruby on Rails and HTML5 development](http://9elements.com/)
                
                1. Hallo molily,

                  Viele Browser unterstützen requestAnimationFrame mit Vendor-Prefix, daher sind die Polyfills, die das berücksichtigen, schon sinnvoller.

                  stimmt, die Safaris sollte ich mit berücksichtigen.

                  Gruß, Jürgen

    2. Ich habe jetzt damit einen simplen Quellcode geschrieben, dass ich ihn auch posten kann.

        
        
      var loop = function(test)  
      	{  
      		if (i <=100)  
      		{  
      			test.style.opacity = i / 100;  
      			window.requestAnimationFrame(loop);  
      			i = i + 0.5;  
      		}  
      	};  
      
      

      Jedoch wird beim aufrufen von loop wieder nur das Endergebnis angezeigt. Gut jetzt dachte ich mir, dass es vielleicht so schnell geht, dass man es nicht sehen kann, jedoch lies es sich mit sleep() dazwischen auch nicht anzeigen.