Hauke: setTimeout

Hallo,

ich habe ein Problem mit setTimeout. Meine Funktion erhöht den CSS-wert height jeweils um 100px. ich will das meine funktion verzögert wird:

function new_tab_parttopic() {  
	  
	var div_height = document.getElementById("new_tab_area");  
	  
	function scroll_down() {  
	var height_change = div_height.offsetHeight;  
	div_height.style.height = height_change + 100 + "px";  
	}  
	  
	setTimeout("scroll_down()", 10000);  
	  
}

auf diese art wird die funktion gar nicht ausgeführt. wenn ich jedoch die anführungszeichen weglasse,

setTimeout(scroll_down(), 10000);

dann wird die funktion zwar ausgeführt, jedoch ohne verzögerung.

was mach ich falsch?

grüße, hauke

  1. auf diese art wird die funktion gar nicht ausgeführt.

    Doch aber nur einmal.

    wenn ich jedoch die anführungszeichen weglasse,
    setTimeout(scroll_down(), 10000);

    Dann musst du auch die Klammern weglassen.

    Struppi.

  2. Hi,

    was mach ich falsch?

    Du berücksichtigst nicht den Kontext, in dem der Aufruf erfolgt.

    Deine Funktion ist eine Methode des Objektes, in dem du dich befindest.

    Wenn du setTimeout(methode(), ...) schreibst, dann wird die Methode direkt zu diesem Zeitpunkt aufgerufen, von innerhalb des Objektes aus - da funktioniert die Zuordnung. (Allerdings bewirkt das natürlich nicht das gewünschte.)

    setTimeout(methode, ...) hingegen legt den Aufruf „auf Halde“, um ihn später durchzuführen - allerdings passiert das dann ausserhalb des Kontextes deines Objektes, und damit ist die Methode dort gar nicht mehr verfügbar.

    Mehr dazu, und auch Lösungsansätze, findest du in diesen Artikeln:
    http://aktuell.de.selfhtml.org/artikel/javascript/fader-framework/
    http://aktuell.de.selfhtml.org/artikel/javascript/organisation/

    MfG ChrisB

    --
    “Whoever best describes the problem is the person most likely to solve the problem.” [Dan Roam]
    1. Hi,

      Du berücksichtigst nicht den Kontext, in dem der Aufruf erfolgt.

      Oder ich verstehe was falsch ...

      setTimeout(methode, ...) hingegen legt den Aufruf „auf Halde“, um ihn später durchzuführen - allerdings passiert das dann ausserhalb des Kontextes deines Objektes, und damit ist die Methode dort gar nicht mehr verfügbar.

      Das ist Unsinn, wenn die Referenz korrekt übergeben wird, dann ist das egal.

      Struppi hat die passende Antwort.

      MfG ChrisB

      --
      “Whoever best describes the problem is the person most likely to solve the problem.” [Dan Roam]
      1. Du berücksichtigst nicht den Kontext, in dem der Aufruf erfolgt.

        Oder ich verstehe was falsch ...

        Du hast übersehen, dass er die Funktion als Code aufruft, d.h. in Anführungszeichen:

        setTimeout("scroll_down()", 10000);

        Du dürftest also richtig gelegen haben: Der Code in den Anführungszeichen wird erst bei Bedarf interpretiert, nicht sofort, und damit ist der Kontext weg.

        Übergibt er hingegen keinen Code, sondern die Funktion selbst, also

        setTimeout(scroll_down, 10000);

        erkennt der Interpreter sie schon beim setTimeout()-Aufruf und kann sie sozusagen zurücklegen.

        1. Du hast übersehen, dass er die Funktion als Code aufruft, d.h. in Anführungszeichen:

          setTimeout("scroll_down()", 10000);

          Du dürftest also richtig gelegen haben: Der Code in den Anführungszeichen wird erst bei Bedarf interpretiert, nicht sofort, und damit ist der Kontext weg.

          Da lag ich wohl falsch - Aber in dem Fall steht auch eine Meldung in der Fehlerkonsole, da sollte Hauke das näxte mal reinschauen.

          Struppi.

    2. Deine Funktion ist eine Methode des Objektes, in dem du dich befindest.

      Es ist bloß eine lokale Funktion. Die ist intern am Variablenobjekt des Execution Contexts gespeichert, das durch den Funktionsaufruf erzeugt wurde.

      setTimeout(methode, ...) hingegen legt den Aufruf „auf Halde“, um ihn später durchzuführen - allerdings passiert das dann ausserhalb des Kontextes deines Objektes, und damit ist die Methode dort gar nicht mehr verfügbar.

      Der Begriff Kontext ist hier irreführend und du verwendest ihn gleich mit zwei unterschiedlichen Bedeutungen. (Die von mir im verlinkten Artikel verwendete Bedeutung ist auch nicht so ganz schlau.)

      setTimeout kann man entweder ein Funktionsobjekt übergeben. Die Referenz auf das Funktionsobjekt muss dort, wo setTimeout aufgerufen wird, natürlich verfügbar sein. D.h. wenn ich setTimeout(foo, 1000) schreibe, dann muss der Bezeichner foo zu einem Funktionsobjekt auflösbar sein.
      Alternativ kann man setTimeout einen String übergeben. Dieser Code wird dann mit eval() ausgeführt.

      Der Execution Context in beiden Fällen ist der globale Kontext. Das bedeutet, dass this auf das globale Objekt (window) verweist. Das, worauf this zeigt, bezeichne ich im Artikel als Kontext. Das hat mit »Methode ist dort nicht verfügbar« nichts zu tun. Verfügbarkeit von Objekten (Referenzierbarkeit) wird immer über den Scope entschieden. Intuitiv würde man eher den als Kontext bezeichnen... wie gesagt, der Begriff ist nicht so tauglich. Der Execution Context beinhaltet sowohl die this-Referenz als auch die maßgebliche Scope Chain.

      Im Falle der Übergabe eines Strings an setTimeout, z.B. "foo()", wird der Bezeichner »foo« am globalen Objekte gesucht. Denn die Scope Chain, also die Liste der Objekte, bei denen nach entsprechenden Membern gesucht wird, enhält nur das globale Objekt. foo muss also eine globale Funktion sein, sonst gibt es eine Exception. Und das war nicht der Fall im geposteten Code.

      Im Falle der Übergabe einer Funktion muss kein Bezeichner aufgelöst werden, sie steht bereits als Referenz zur Verfügung. Die Referenz hat kein base object, deshalb wird das globale Objekt angenommen - daher this == window. (Selbst man setTimeout(objekt.methode, 1000) notieren wurde, dann geht diese Basis verloren.)

      Ganz anderes thema: Welche Variablen dem Code IN der Funktion zur Verfügung stehen, hängt davon ab, in welchem Execution Context sie ERZEUGT wurde. Wenn wir uns dieses Beispiel noch einmal ansehen:

      function new_tab_parttopic()  {
         var div_height = document.getElementById("new_tab_area");
         function scroll_down() {
            var height_change = div_height.offsetHeight;
            div_height.style.height = height_change + 100 + "px";
         }
         setTimeout(scroll_down, 10000);
      }

      Hier haben wir es mit einer Closure zu tun. Die Scope Chain der scroll_down-Funktion enthält das eigene Variablenobjekt, das Variablenobjekt des new_tab_parttopic()-Aufrufs und schließlich das globale Objekt. Damit kann man darin - auch später noch, wenn scroll_down durch setTimeout im globalen Execution Context ausgeführt wird - auf die Variable div_height zugreifen. Der Execution Context samt Variablenobjekt wird nämlich erhalten.

      Mathias