mb: caught exception: out of memory

anbend, der FireBug spuckt bei mir folgenden ErrorMessage aus: caught exception: out of memory bei diesem Code:


function Fade(elem, array, ms) {
  // Variable
  this.elem  = elem;    // Bild
  this.array = array;   // URLs
  this.ms    = ms;      // Milisekunden

  // Methods
  this.fading = function() {	
    var count = 0;
    alert(this.elem + "\n" + this.array + "\n" + this.ms);
    var stepping = window.setTimeout(function() {
      alert(this.elem + "\n" + this.array + "\n" + this.ms);
      this.elem.style.backgroundImage = this.array[count];
      if (count > array.length) window.clearTimeout();
      count++;
    }, this.ms);
  }
}

beim ersten alert gibt er noch definierte werte an. erst beim zweiter alert gibt der 3 mal undfined aus. Ich hab n konstruktor gebaut mit Bildwechsel. den halben Tag hab ich gegoogel, bis ich herausgefunden hab, das sich die Werte verändern :/ und ich weis nicht wieso. schon mal dank im voraus Liebe Grüße mb

  1. Guten Abend,

    
    function Fade(elem, array, ms) {
      // Variable
      this.elem  = elem;    // Bild
      this.array = array;   // URLs
      this.ms    = ms;      // Milisekunden
    
      // Methods
      this.fading = function() {	
        var count = 0;
        alert(this.elem + "\n" + this.array + "\n" + this.ms);
        var stepping = window.setTimeout(function() {
          alert(this.elem + "\n" + this.array + "\n" + this.ms);
          this.elem.style.backgroundImage = this.array[count];
          if (count > array.length) window.clearTimeout();
          count++;
        }, this.ms);
      }
    }
    

    beim ersten alert gibt er noch definierte werte an. erst beim zweiter alert gibt der 3 mal undfined aus. Ich hab n konstruktor gebaut mit Bildwechsel. den halben Tag hab ich gegoogel, bis ich herausgefunden hab, das sich die Werte verändern :/ und ich weis nicht wieso.

    Bei deinem ersten Alert befindest du dich mit dem Scope bei deinem Fade Object, welches die Eigenschaften elem, array und ms besitzt.
    Bei deinem zweiten Alert befindest du dich allerdings mit dem Scope beim window (setTimeout). window besitzt keine der Eigenschaften elem, array oder ms; somit bekommst du undefined zurück.

    Du kannst setTimeout Parameter mitgeben: setTimeout(fn(elem, array){}, this.ms, this.elem, this.array);

    Der erste Parameter ist für die Funktion, der Zweite gibt die Millisekunden an. Alle weiteren sind optional; falls anwesend werden sie der angegebenen Funktion übergeben.

    Vielleicht schaffe ich es später dir noch ein wenig Lektüre dazu mit auf den Weg zu geben. (Vielleicht könnte sich auf jemand anderes darum kümmern - ich bin morgen erst spät wieder da)

    Reinhard

  2. Lieber mb,

    das Schlüsselwort "this" hat je nach Kontext ganz andere Bedeutungen. Es bezieht sich innerhalb der Funktion, die Du dem setTimeout als ersten Parameter übermittelst, auf das window-Objekt. Die Variable "this" ist daher dort eine völlig andere, als noch zuvor im Scope der fading-Methode.

    Hier ist eine übliche Lösung:

    Function Fade (elem, array, ms) {
        // Variable
        this.elem  = elem;    // Bild
        this.array = array;   // URLs
        this.ms    = ms;      // Milisekunden
    
        // Methods
        this.fading = function () {
            var count = 0;
            var that = this; // für den setTimeout-Kontext später
    
            var stepping = window.setTimeout(function () {
                // that != this!
                that.elem.style.backgroundImage = that.array[count];
                // [...]
            }, this.ms);
        };
    }
    

    Warum willst Du den Rückgabewert von setTimeout speichern? Die übermittelte Funktion wird eh nur einmal ausgeführt! Da lohnt es sich ja kaum, den timeout wieder zu löschen! Dazu verwendest Du clearTimeout() ohne irgendeine Angabe (das müsste clearTimeout(stepping) heißen!), was mich zu der Frage bringt, was Du da eigentlich tust.

    Liebe Grüße,

    Felix Riesterer.

    1. Nachtrag:

      dass die anonyme Funktion, die dem setTimeout-Aufruf als ersten Parameter übermittelt wird, die Variable "that" überhaupt kennt, liegt an einem sehr mächtigen Sprach-Feature von JavaScript, das man "Closure" nennt. Die Variable "that" wird in der anonymen Funktion sozusagen eingekapselt, sodass sie, wenn denn der Timeout eintritt, den Wert dieser Variablen noch weiß, auch wenn der fading()-Aufruf längst abgearbeitet wurde.

      Liebe Grüße,

      Felix Riesterer.

      1. dass die anonyme Funktion, die dem setTimeout-Aufruf als ersten Parameter übermittelt wird, die Variable "that" überhaupt kennt, liegt an einem sehr mächtigen Sprach-Feature von JavaScript, das man "Closure" nennt.

        stimmt Danke Dir. Ich hab mich mit den Begriffen Closures und that = this schon auseinander gesetzt. Ich komme ursprünglicxh aus der Java Ecke und Closures nehme ich an sind nichts weiter als Private Methoden oder Konstruktoren. Danke euch Reihard und Felix. Ich vermute ich werd SelfHTML noch mal nerven wofür ich mich jetzt schon entschuldige :/. Herzlichste Grüße mb

    2. Hier ist eine übliche Lösung:

      Function Fade (elem, array, ms) {
          // Variable
          this.elem  = elem;    // Bild
          this.array = array;   // URLs
          this.ms    = ms;      // Milisekunden
      
          // Methods
          this.fading = function () {
              var count = 0;
              var that = this; // für den setTimeout-Kontext später
      
              var stepping = window.setTimeout(function () {
                  // that != this!
                  that.elem.style.backgroundImage = that.array[count];
                  // [...]
              }, this.ms);
          };
      }
      

      Alternativ kann man den this-Kontext von der Callbackfunktion auch an den this-Kontext der äußeren Funktion binden:

      var stepping = window.setTimeout(function () {
         this.elem.style.backgroundImage = this.array[count];
         // [...]
      }.bind(this), this.ms);
      

      In der neusten JavaScript-Version gibt es sogar eine verkürzte Funktionsschreibweise, die diesen Schritt obsolet macht:

      var stepping = window.setTimeout(() =>
         this.elem.style.backgroundImage = this.array[count];
      // [...]
      }, this.ms);
      

      Eine radikalere Lösung besteht darin, this vollständig zu vermeiden und mit Factories anstatt mit Konstruktoren zu arbeiten:

      function createFade (elem, array, ms) {
      
          function fading () {
              var count = 0;
              var stepping = window.setTimeout(function () {
                  elem.style.backgroundImage = array[count];
                  // [...]
              }, ms);
          }
      
          return { fading }; //ES2015 Syntax, für ES5.1: return { fading : fading }
      }
      

      Und nur so zum Spaß noch eine funktionale Variante ohne veränderliche Zustandsvariablen, dafür mit Promises, um den Kontrollfluss zu modellieren:

      function reduceWithDelay (fn, array, delay) {
         return array.reduce((lastPromise,nextElement) =>
            new Promise(resolve =>
               lastPromise.then(()=>setTimeout(()=>{
                  fn(nextElement)
                  resolve();
               }, delay))
            ), (new Promise(resolve=>resolve())));
      }
      
      const animation = reduceWithDelay(color=>document.body.style.backgroundColor=color, ['red','green'], 1000);
      animation.then(()=>console.log('Animation fertig'));
      

      http://jsfiddle.net/sftvptzv/ (getestet mit Chrome)

      1. schöne Lösungen 1unitedpower :) und ich werds mir ansachauen, aber das hilft bei diesem Problem nicht weiter :/.

  3. Erst einmal herzlichen Dank. Mir ist jetzt einiges im quellcode klar geworden. das mit dem setTimeout und mit der übergabe funzt jetzt.

    function Fade(elem, array, ms) {
      // Variable
      this.elem	= elem;
      this.array	= array;
      this.ms		= ms;
      // Methods
      this.fading = function() {	
        var that = this;
        var count = 0;
        var stepping = window.setInterval(function () {
          if (count >= array.length -1) {
            window.clearInterval(stepping);
            that.elem.style.display = "none";
          } else {
            that.elem.style.backgroundImage = "" + that.array[count];
            count++;
          }
          alert(that.elem.style.backgroundImage + "\n" + that.array[count] + "\n" + that.ms + "\n" + count);
        }, this.ms);
      }
    }
    

    aber ich habe immer noch das problem mit

    uncaught exception: out of memory
    

    beim alert gibt er mir seh schon alle paraqmeter zurück auch die URLs, aber that.elem.style.backgroundImage ist leer und bei der HTML-Ausgabe auche ich n leeren String bei Style obwohl er mir style im HTML als Attribut angelegt hat. nur leer eben :/. am ender des setTimeout() kommt display: none was ja korrekt war;

    <div id="screen" style=""></div>
    

    Meine leihenhafte vermutung das irgendwas mit der übergabe vom array net stimmt. alles andere habe ich überprüft.

    1. ach ja für die lösung des problem sollte ich den externen Quellcode dazu schreiben

      <script type="text/javascript" src="lib/js/fade.js"></script>
      <script type="text/javascript">
      window.onload = function() {
        var fade_1000	= "../../media/images/fade_1000.png",
            fade_875	= "../../media/images/fade_875.png",
            fade_750	= "../../media/images/fade_750.png",
            fade_625	= "../../media/images/fade_625.png",
            fade_500	= "../../media/images/fade_500.png",
            fade_375	= "../../media/images/fade_375.png",
            fade_250	= "../../media/images/fade_250.png",
            fade_125	= "../../media/images/fade_125.png",
            fade_0	= "../../media/images/fade_0.png",
            imageFade	= new Array(fade_1000, fade_875, fade_750, fade_625, fade_500, fade_375, fade_250, fade_125, fade_0);
        var elem = document.getElementById("Screen");
        var sceenFade = new Fade(Screen, imageFade, 125);
         ScreenFade.fading();
      }
      </script>
      

      die Bilder sind n pixel groß und wiederholen sich immer wieder im <div>-Conainer wenns funzt :/

      1. Hallo mb,

          var elem = document.getElementById("Screen");
          var sceenFade = new Fade(Screen, imageFade, 125);
           ScreenFade.fading();
        

        ist hier evtl. ein Fehler drin? Vergleiche elem und Screen bzw. sceenFade und ScreenFade.

        Gruß, Dennis

        1. hallo dennis

          ist hier evtl. ein Fehler drin? Vergleiche elem und Screen bzw. sceenFade und ScreenFade.

          ich habs veränder zum besseren Verständnis. Alles ist richtig implementiert. das problem ist weinzig ud allein

          that.elem.style.backgroundImage = "" + that.array[count];
          

          Der Übergabe Array mit URLs funzt, Style in JavaScript auch aber die Übergabe der Style-Elemente net :(

    2. Morgen,

        this.fading = function() {	
            if (count >= array.length -1)
      

      Wenn ich das richtig sehe, dann liegt hier das Problem. Du hast in der Funktion keine Variable array definiert. Versuche es mal mit that.array.length.

      Reinhard

      1. Morgen Reinhard, leider nicht. Gute idee das mit that.array -1. hab korrigiert aber ist der selbe Fehler

          this.fading = function() {	
              if (count >= array.length -1)
        

        Wenn ich das richtig sehe, dann liegt hier das Problem. Du hast in der Funktion keine Variable array definiert. Versuche es mal mit that.array.length.

        that.array[count];
        

        is n Array mit den URL-Werten und ich kann drauf zugreifen

        that.elem.style.backgroundImage = "" + that.array[count];
        

        das <div>-Tag "elem" in JavaScript Variable erzeugt ein Style-Attribut aber leer :/ leer obwohl ich die URLs übergeben habe

        alert(that.elem.style.backgroundImage);
        

        gibt nix aus. Es ist leer in jedem URL-Sting vom Array :(

        1. Morgen,

          also, ich habe mir einen Augenblick genommen um deinen Fader zu testen.
          Immer schön auf Groß- und Kleinschreibung achten, dann sollte es auch funktionieren.

              <div id="screen"></div>
          
                #screen {
                    width: 100%;
                    height: 60vh;
                    background-color: #06F;
                    border: 3px solid #F00;
                }
          
                function Fade(elem, array, ms) {
                    this.elem = elem;
                    this.array = array;
                    this.ms = ms;
                    this.fading = function() {
                        var that = this,
                            count = 0,
                            stepping = setInterval(function() {
                                if (count >= that.array.length)
                                  {
                                  clearInterval(stepping);
                                  that.elem.style.display = 'none';
                                  }
                                 else
                                  that.elem.style.backgroundImage = 'url(' + that.array[count++] + ')';
                            }, this.ms);
                    };
                }
                
                document.addEventListener('DOMContentLoaded', function() {
                    var elem = document.getElementById('screen'),
                        array = ['chrome://global/skin/media/imagedoc-darknoise.png', 'chrome://global/skin/media/imagedoc-lightnoise.png'];
                    array.push.apply(array, array.slice());
                    array.push.apply(array, array.slice());
                    var fader = new Fade(elem, array, 2000);
                    fader.fading();
                });
          

          Den Inhalt von array (chrome://global …) einfach mit deinen URL's austauschen.
          array.push.apply(array, array.slice()); vervielfältigt lediglich den Inhalt von array. Habe ich zum testen verwendet. Kannst du weglassen.

          Reinhard

          1. Guten Mittag,

            ich bin mit alert() und firebug intensiv auf fehlersuche gegangen. alles läuft alles ok nur die übergabe an das style-Element läuft was schief. wenn da nur ne referenz auftauche würde wäre ja alles ok, aber das ist noch nicht einmal der Fall. alles was ich sehe nachdem ich diesen Befehl

            document.getElementById("htmlObjekt");
            
            htmlObjekt.style.backgroundImage = "nBild.png";
            

            ausgeführt habe ist

            <div id="htmlObjekt" style=""></div>
            

            und kann es auch so lauten wie du es geschrieben hast?

            htmlObjekt.style.backgroundImage = url( + "nBild.png" + );
            

            viele Grüße mb

            1. Guten Abend,

              htmlObjekt.style.backgroundImage = url( + "nBild.png" + );
              

              Wenn du kein <img> benutzen möchtest, sondern background-image, so musst du es - wenn schon denn schon - so aufschreiben:

              htmlObjekt.style.backgroundImage = "url(" + _bildpfad_ + ")";
              

              Was stimmt denn nicht mit dem Beispiel, das ich dir gegeben habe?

              Wenn du das ganze lokal ausprobierst musst du ggf. vor dem Pfad ein file:/// anführen.

              Reinhard

              1. htmlObjekt.style.backgroundImage = "url(" + _bildpfad_ + ")";
                

                ja stimmt, mir fällts wieder ein. Das Problem besteht immernoch das JavaScript im Stye-Element die URLs nicht übergibt :/

                Was stimmt denn nicht mit dem Beispiel, das ich dir gegeben habe?

                Alles gut. ich hab mich nur etwas falsch ausgedrückt. tschuldige bitte. Ich vermute mal das ist n syntaxtischer fehler irgendwo in meinem Code-konstrukt. Ich melde mich wenn ichs gelöst habe. matrial und beispiele habe ich ja dank euch. Guten Abend, mb

                1. Abend allerseits,

                  htmlObjekt.style.backgroundImage = "url(" + _bildpfad_ + ")";
                  

                  komischerweise gehts jetzt wegen eines einzigen semikolons.

                  htmlObjekt.style.backgroundImage = "url(" + _bildpfad_ + ");";
                  

                  Ich danke euch - dir Reinhard - sehr. Schönen Abend mb