nam: Race Condition?

Hallo

Ich arbeite an einer Website für eine Band. Nun habe ich ein Script zusammengestöpselt, dass links auf '.mp3' sucht und diese durch einen kleinen Flash-Player ersetzt, so dass man die Musik direkt auf der Seite hören kann.

  
var mp3player = (function () {  
  
	var aTags;  
	  
	return {  
		init : function () {  
			var key, l, i;  
			aTags = document.getElementsByTagName('a');  
			l = aTags.length;  
			for (i = 0; i <= l; i++) {  
				if (aTags[i].href) {  
					if (aTags[i].href.match(/\.mp3$/i)) {  
						mp3player.insert(aTags[i]);  
					}  
				}  
			}  
		},  
		insert: function (tag) {  
			var flobj = null,  
			param = null;  
			  
			flobj = document.createElement('object');  
			flobj.type = 'application/x-shockwave-flash';  
			flobj.data = 'js/player_mp3_mini.swf';  
			flobj.width = '200';  
			flobj.height = '20';  
			  
			param = document.createElement('param');  
			param.name = 'movie';  
			param.value = 'js/player_mp3_mini.swf';  
			flobj.appendChild(param);  
			  
			param = document.createElement('param');  
			param.name = 'bgcolor';  
			param.value = '#eeeeee';  
			flobj.appendChild(param);  
			param = document.createElement('param');  
			param.name = 'FlashVars';  
			param.value = 'mp3=' + tag.href;  
			flobj.appendChild(param);  
			tag.parentNode.replaceChild(flobj, tag);  
		}  
	};  
  
}());  
  
if (window.onload) {  
	var f = window.onload;  
	window.onload = function () {  
		f();  
		mp3player.init();  
	};  
} else {  
	window.onload = function () {  
		mp3player.init();  
	};  
}

Das Problem ist nun, dass sich aTags, bzw. aTags.length während des Durchlaufs der for-Schleife ändert (Race Condition) und dann nicht alles ersetzt wird.

Wie macht man das richtig?

Danke und Gruss,
Mathias

  1. Hallo!

    Abgesehen von der recht schönen Objektorientierung machst Du es Dir an einigen Stellen unnötig kompliziert:

      		if (aTags[i].href) {  
      			if (aTags[i].href.match(/\.mp3$/i)) {  
    

    Wozu brauchst Du das Ergebnis der RegExp?

    if (!/\.mp3$/i.test(aTags[i].href || '')) { continue; }  
    this.insert(aTags[i]);
    

    erfüllt gleich beide Bedingungen und ist auch noch eleganter.

    if (window.onload) {
    var f = window.onload;
    window.onload = function () {
    f();
    mp3player.init();
    };
    } else {
    window.onload = function () {
    mp3player.init();
    };
    }

    Hier kann man auch gleich eine Closure verwenden:

    window.onload = function(o) { return function() {  
        if (o) { o(); }  
        mp3player.init();  
    }}(window.onload);
    

    Das Problem ist nun, dass sich aTags, bzw. aTags.length während des Durchlaufs der for-Schleife ändert (Race Condition) und dann nicht alles ersetzt wird.

    Das kann nur passieren, wenn im bisherigen Onload etwas mit Verzögerung die Links verändert. In diesem Fall prüfe die Erledigung eines derartigen Scripts, bevor Du die init-Methode startest. Ansonsten solltest Du in dem Fall, in dem Du einen Link mit "insert" ersetzt, vorher nochmal nachfragen, ob es diesen überhaupt noch gibt.

    Gruß, LX

    --
    RFC 1925, Satz 6a: Es ist immer möglich, einen weiteren Umweg einzufügen.
    RFC 1925, Satz 11a: Siehe Regel 6a
    1. Hallo,

      Abgesehen von der recht schönen Objektorientierung

      Ja, Kompliment! Sowas sieht man hier selten.

      Ansonsten solltest Du in dem Fall, in dem Du einen Link mit "insert" ersetzt, vorher nochmal nachfragen, ob es diesen überhaupt noch gibt.

      Ja, und außerdem hilft m.E. dann nur, das Array nach jeder Ersetzung neu zu erstellen und wieder bei 0 anzufangen in der Scheife. Irgendwann müssen die Links ja aufhören sich zu ändern.

      Gruß, Don P

    2. Hi LX

      Danke für die Tipps. Da lernt man wieder was…

      Mein Problem ist damit aber leider nicht gelöst.
      Die Links sind da, wenn das Script ausgeführt wird. Während der Ausführung ändert aber das Script das aTags-Array (weil es ja a-Elemente löscht/ersetzt) und es kann dann nicht mehr auf alle Elemente zugreifen.
      Habs auch mit for…in probiert, aber selbes Problem.

      Jedesmal das aTags-Array neu aufzubauen ist wohl nicht wirklich performant?

      Hmm.

      Werde mal versuchen mit einem Buffer zu arbeiten und dann alle a-Elemente in einem Wisch zu ersetzen.

      1. Verwende document.links in einer while-Schleife:

        var l = document.links.lenght;
        while (l--) { if (...) { this.init(document.links[l]); } }

        Problem gelöst.

        Gruß, LX

        --
        RFC 1925, Satz 6a: Es ist immer möglich, einen weiteren Umweg einzufügen.
        RFC 1925, Satz 11a: Siehe Regel 6a
      2. Jetzt geht's!
        Danke für's auf die Sprünge helfen.

          
        var mp3player = (function () {  
          
        	var aTags,  
        	elBuffer = {},  
        	toBuffer = function (el) {  
        		if (!elBuffer[el]) {  
        			elBuffer[el] = el;  
        		}  
        	},  
        	replace = function (tag) {  
        		var flobj = null,  
        		param = null;  
        		  
        		flobj = document.createElement('object');  
        		flobj.type = 'application/x-shockwave-flash';  
        		flobj.data = 'js/player_mp3_mini.swf';  
        		flobj.width = '200';  
        		flobj.height = '20';  
        		  
        		param = document.createElement('param');  
        		param.name = 'movie';  
        		param.value = 'js/player_mp3_mini.swf';  
        		flobj.appendChild(param);  
        		  
        		param = document.createElement('param');  
        		param.name = 'bgcolor';  
        		param.value = '#eeeeee';  
        		flobj.appendChild(param);  
        		param = document.createElement('param');  
        		param.name = 'FlashVars';  
        		param.value = 'mp3=' + tag.href;  
        		flobj.appendChild(param);  
        		tag.parentNode.replaceChild(flobj, tag);  
        	},  
        	replaceAllInBuffer = function () {  
        		var key;  
        		for (key in elBuffer) {  
        			if (elBuffer.hasOwnProperty(key) && elBuffer[key]) {  
        				replace(elBuffer[key]);  
        				elBuffer[key] = false;  
        			}  
        		}  
        	};  
        	  
        	return {  
        		init : function () {  
        			var key;  
        			aTags = document.getElementsByTagName('a');  
        			for (key in aTags) {  
        				if (aTags.hasOwnProperty(key)) {  
        					if (!/\.mp3$/i.test(aTags[key].href || '')) {  
        						continue;  
        					}  
        					toBuffer(aTags[key]);  
        				}  
        			}  
        			replaceAllInBuffer();  
        		}  
        	};  
          
        }());  
          
        window.onload = (function (o) {  
        	return function () {  
        		if (o) {  
        			o();  
        		}  
        		mp3player.init();  
        	};  
        }(window.onload));  
        
        
        1. naja

          Ich scheine der Meister des Komplizierten zu sein.
          LX's Lösung (Siehe oben) ist viel einfacher.

          1. Das Ziel eines JS-Entwicklers sollte immer sein, die denkbar einfachste Lösung für jedes noch so komplexe Problem zu finden.

            Gruß, LX

            --
            RFC 1925, Satz 6a: Es ist immer möglich, einen weiteren Umweg einzufügen.
            RFC 1925, Satz 11a: Siehe Regel 6a
            1. Hallo,

              Das Ziel eines JS-Entwicklers sollte immer sein, die denkbar einfachste Lösung für jedes noch so komplexe Problem zu finden.

              ich würde das nicht auf JS beschränken.
              Dieses Ziel ist in allen Lebenslagen erstrebenswert!

              Ciao,
               Martin

              --
              Keine Sorge, wir finden für jede Lösung ein Problem.
            2. Das Ziel eines JS-Entwicklers sollte immer sein, die denkbar einfachste Lösung für jedes noch so komplexe Problem zu finden.

              Die richtige, nicht die einfachste.

              Es scheint einfach, Elemente im DOM durch andere Elemente zu ersetzen. Aber ist es auch richtig?

              mfg Beat

              --
              ><o(((°>           ><o(((°>
                 <°)))o><                     ><o(((°>o
              Der Valigator leibt diese Fische
              1. Hi,

                Das Ziel eines JS-Entwicklers sollte immer sein, die denkbar einfachste Lösung für jedes noch so komplexe Problem zu finden.

                Die richtige, nicht die einfachste.

                Es scheint einfach, Elemente im DOM durch andere Elemente zu ersetzen. Aber ist es auch richtig?

                Das kommt immer auf den konkret vorliegenden Fall an.

                Wenn du im vorliegenden Fall diesbezüglich Bedenken hast - welche wären das?

                MfG ChrisB

                --
                “Whoever best describes the problem is the person most likely to solve the problem.” [Dan Roam]
                1. Das Ziel eines JS-Entwicklers sollte immer sein, die denkbar einfachste Lösung für jedes noch so komplexe Problem zu finden.
                  Die richtige, nicht die einfachste.
                  Es scheint einfach, Elemente im DOM durch andere Elemente zu ersetzen. Aber ist es auch richtig?

                  Das kommt immer auf den konkret vorliegenden Fall an.
                  Wenn du im vorliegenden Fall diesbezüglich Bedenken hast - welche wären das?

                  Elemente erzeugen einen Kontext. Im konkreten Fall ist zwar keine Regelverletzung vorliegend, da dort, wo ein a Element stehen darf, auch ein object Element erlaubt ist.
                  Verallgemeinert würde ich jedoch eine Lösung bevorzugt, welchen den Kontext, in welchem das zu ersetzende Element steht, überprüft.

                  mfg Beat

                  --
                  ><o(((°>           ><o(((°>
                     <°)))o><                     ><o(((°>o
                  Der Valigator leibt diese Fische
                  1. Hi,

                    Elemente erzeugen einen Kontext. Im konkreten Fall ist zwar keine Regelverletzung vorliegend, da dort, wo ein a Element stehen darf, auch ein object Element erlaubt ist.

                    Was wäre deine Alternative dazu, Element im DOM durch andere Elemente zu ersetzen?
                    Neue Elemente zusätzlich zu den bestehenden ins Dokument einzuhängen? Auch da musst du dir überlegen, wo diese erlaubt sind und wo nicht.

                    Verallgemeinert würde ich jedoch eine Lösung bevorzugt, welchen den Kontext, in welchem das zu ersetzende Element steht, überprüft.

                    Das macht der Browser.
                    Der Versuch, ein Element im DOM an einer Position einzuhängen, wo es nicht stehen darf, wird mit einem Laufzeitfehler quitiert.

                    MfG ChrisB

                    --
                    “Whoever best describes the problem is the person most likely to solve the problem.” [Dan Roam]
                    1. Elemente erzeugen einen Kontext. Im konkreten Fall ist zwar keine Regelverletzung vorliegend, da dort, wo ein a Element stehen darf, auch ein object Element erlaubt ist.

                      Was wäre deine Alternative dazu, Element im DOM durch andere Elemente zu ersetzen?
                      Neue Elemente zusätzlich zu den bestehenden ins Dokument einzuhängen? Auch da musst du dir überlegen, wo diese erlaubt sind und wo nicht.

                      Ich hänge im allgemeinen Elemente nicht blind ins Dom, sondern an vordefinierten Stellen.

                      Konkret handelt es sich ja nicht um eine geeignete library Funktion (dazu arbeitet sie zu pauschal).
                      Ein erlaubter Kontext kann im HTML zum Beispiel durch die explizite classe versichert werden.
                      Meine Funktion würde eher
                      <div class="mp3player"><a .../></div>
                      voraussetzen, und müsste zumal nicht einmal das a Element ersetzen. display:none reicht ja, wobei ich mich im konkreten Fall auch Frage, warum man den Downloadlink eigentlich entfernen muss.

                      Verallgemeinert würde ich jedoch eine Lösung bevorzugt, welchen den Kontext, in welchem das zu ersetzende Element steht, überprüft.

                      Das macht der Browser.
                      Der Versuch, ein Element im DOM an einer Position einzuhängen, wo es nicht stehen darf, wird mit einem Laufzeitfehler quitiert.

                      dem man mit try/catch behandeln vorbeugen muss.

                      mfg Beat

                      --
                      ><o(((°>           ><o(((°>
                         <°)))o><                     ><o(((°>o
                      Der Valigator leibt diese Fische
                      1. Hi,

                        Ich hänge im allgemeinen Elemente nicht blind ins Dom, sondern an vordefinierten Stellen.

                        Das sehe ich als Selbstverständlichkeit an.

                        Ein erlaubter Kontext kann im HTML zum Beispiel durch die explizite classe versichert werden.

                        Nein, überhaupt nicht.

                        In <h1 class="..."> wirst du kein DIV oder TABLE einhängen können - ganz egal, was du für die ... als realen Wert des class-Attributes einsetzt.

                        Meine Funktion würde eher
                        <div class="mp3player"><a .../></div>
                        voraussetzen,

                        Gut, könnte sie machen.

                        Das macht sie aber nicht "sicherer" gegen Fehler, wenn sie auf ein Element trifft, welches diese Voraussetzung erfüllt, aber trotzdem technisch ungeeignet ist, entsprechend behandelt zu werden.
                        Dass dieser Fall nicht auftreten „kann”, ist aber reine Konvention - von dir ist *ausserhalb* des Einflussbereiches des Scriptes definiert, dass nur solche Elemente überhaupt diese Klasse besitzen dürfen, die sich auch für die vorgesehene Bearbeitung eignen.

                        und müsste zumal nicht einmal das a Element ersetzen. display:none reicht ja, wobei ich mich im konkreten Fall auch Frage, warum man den Downloadlink eigentlich entfernen muss.

                        Ob man das macht oder nicht, ist für diese Diskussion nebensächlich.

                        Verallgemeinert würde ich jedoch eine Lösung bevorzugt, welchen den Kontext, in welchem das zu ersetzende Element steht, überprüft.

                        Wie weit in welche Richtung man den Schieberegler, der auf der einen Seite mit "vorgegebener Kontext, in dem die Funktion korrekt arbeitet" und auf der anderen mit "eierlegende Wollmilchsau" beschriftet ist, verschiebt, macht man auch vom konkreten Einsatzzweck abhängig.

                        Ich würde in einem Fall wie dem vorliegenden dazu tendieren, die Anforderungen an den Kontext konkreter und restriktiver vorzugeben, anstatt eine Funktion/Methode zu schreiben, die zwar mit wirklich "allem", worauf man sie eventuell zur Anwendung bringen könnte, umgehen kann, dafür aber auch entsprechend "bloated" ist.

                        Das macht der Browser.
                        Der Versuch, ein Element im DOM an einer Position einzuhängen, wo es nicht stehen darf, wird mit einem Laufzeitfehler quitiert.

                        dem man mit try/catch behandeln vorbeugen muss.

                        Diese Notwendigkeit habe ich eigentlich noch so gut wie nie gesehen.
                        (Darüber, wofür man try/catch benutzen sollte, und wofür nicht, hatten wir hier auch schon umfangreichere Diskussionen.)

                        Das ist für mich vergleichbar damit, in jedem Script erst mal mit
                        if(document.getElementById) { ...
                        zu beginnen.
                        Ja, mag nach „reiner Lehre” vielleicht angebracht sein - halte ich in der Praxis aber für Nonsense.
                        In einem Browser, der nicht mal diese Methode kennt, möchte ich mit DOM Scripting gar nicht erst anfangen.
                        Ob irgendein Nutzer, der heutzutage noch einen archaischen Browser benutzt, mit dem schon der T-Rex nach oben-ohne-Bildchen von Artgenossinen im damals noch jungen Internet gesucht hat, eine Script-Fehlermeldung zu sehen bekommt, weil ich auf diese essentielle Prüfung verzichte, ist mir absolut egal.
                        Der Wunsch nach (Abwärts-)Kompabilität zu noch so absurden und widrigen Umgebungsbedingungen wird irgendwann zu einem Aufwand, der sich einfach nicht mehr lohnt.

                        Und ähnlich sehe ich das auch hier.
                        Wenn die Bedinungen, unter denen das Script laufen soll, hinreichend klar umrissen sind, und auch bei der Erstellung der HTML-Dokumente schon berücksichtigt werden - dann prüfe ich mir keinen Wolf an Stellen, an denen ich das gar nicht für notwendig erachte.
                        Die universelle Verwendbarkeit meiner Lösung mag darunter etwas leiden - aber wie schon gesagt, wie weit man den erwähnten Schieberegler schiebt, ist vom jeweils aktuellen Fall abhängig.

                        MfG ChrisB

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

                          dem man mit try/catch behandeln vorbeugen muss.

                          Diese Notwendigkeit habe ich eigentlich noch so gut wie nie gesehen.

                          Ich schon. Zu meiner Überraschung musste ich feststellen, dass sich z.B. die Fehlerkonsole von Firefox manchmal ausschweigt, obwohl ein gravierender Fehler vorliegt, den man dann nur noch mit try/catch entlarven kann, wenn man ahnt, wo er evtl. auftritt.

                          Das ist für mich vergleichbar damit, in jedem Script erst mal mit
                          if(document.getElementById) { ...
                          zu beginnen.

                          Grade gestern hab' ich eine lange Diskussion zu cross-Browser Eventhandling durchgelesen. Sie stammt von anno 2005, und man hat sich damals noch alle Mühe gegeben, auch den IE5 und womöglich sogar NS4 noch mitzunehmen. Gegen Ende der Diskussion mustte ich dann lesen, dass neuere IEs statt nur attachEvent/detachEvent auch die entsprechenden W3C-Methoden kennt. Jetzt bin ich vollends verwirrt und fage mich: Soll man ggf. die Kapriolen, die dort gemacht werden, mitmachen, oder reicht es, einfach die W3C-Methoden zu benutzen, d.h. einfach vorausssetzen?
                          "Da steh' ich nun ich armer Tor, und bin so klug als wie zuvor."

                          Gruß, Don P

                          1. Hi!

                            (...): Soll man ggf. die Kapriolen, die dort gemacht werden, mitmachen, oder reicht es, einfach die W3C-Methoden zu benutzen, d.h. einfach vorausssetzen?

                            Da man heutzutage voraussetzen kann, dass normale Nutzer nichts älteres haben als den IE6, kann man durchaus in aller Seelenruhe die node.on[event]-Handler verwenden. Wenn sie nicht verstanden werden, wird das entsprechende Event einfach nicht gesetzt, einen Fehler gibt es dadurch jedoch nicht, da neue Instanzen innerhalb von Nodes durchaus zulässig sind.

                            "Da steh' ich nun ich armer Tor, und bin so klug als wie zuvor."

                            Möge Dir Goethes Faust (oder sonstwer) Erleuchtung einhämmern :-)

                            Gruß, LX

                            --
                            RFC 1925, Satz 6a: Es ist immer möglich, einen weiteren Umweg einzufügen.
                            RFC 1925, Satz 11a: Siehe Regel 6a
                          2. Hi,

                            dem man mit try/catch behandeln vorbeugen muss.

                            Diese Notwendigkeit habe ich eigentlich noch so gut wie nie gesehen.

                            Ich schon. Zu meiner Überraschung musste ich feststellen, dass sich z.B. die Fehlerkonsole von Firefox manchmal ausschweigt, obwohl ein gravierender Fehler vorliegt, den man dann nur noch mit try/catch entlarven kann, wenn man ahnt, wo er evtl. auftritt.

                            Beispiel (mit Bezug zum konkreten Fall)?

                            Grade gestern hab' ich eine lange Diskussion zu cross-Browser Eventhandling durchgelesen. Sie stammt von anno 2005, und man hat sich damals noch alle Mühe gegeben, auch den IE5 und womöglich sogar NS4 noch mitzunehmen. Gegen Ende der Diskussion mustte ich dann lesen, dass neuere IEs statt nur attachEvent/detachEvent auch die entsprechenden W3C-Methoden kennt.

                            K.A., worauf sich das jetzt konkret bezieht. (Btw., bei jedem Kommentar dort ist direkt ein Anker-Link angegeben.)

                            MfG ChrisB

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

                              Zu meiner Überraschung musste ich feststellen, dass sich z.B. die Fehlerkonsole von Firefox manchmal ausschweigt, obwohl ein gravierender Fehler vorliegt, den man dann nur noch mit try/catch entlarven kann, wenn man ahnt, wo er evtl. auftritt.

                              Beispiel (mit Bezug zum konkreten Fall)?

                              Kann ich jetzt nicht mehr liefern, weil der entsprechende Code dann so verbessert wurde, dass das nicht mehr passiert. Aber es es waren immer Eventhanderfunktionen, in denen das Phänomen auftrat. Da ich zur Zeit intensiv mit Events um mich werfe (eine Handlerfunktion wirft einen weiteren Event und dessen Funktion evtl. noch einen), kann es anscheinend passieren, das der FF mit dem Fehlerprotokoll nicht mehr mitkommt und einfach nichts anzeigt. Man merkt dann nur noch am Fehlverhalten der ganzen Applikation, das da irgendwas nicht stimmen kann. Ein try/catch an der richtigen Stelle bringt aber den Fehler ans Licht.

                              K.A., worauf sich das jetzt konkret bezieht. (Btw., bei jedem Kommentar dort ist direkt ein Anker-Link angegeben.)

                              In der Zusammenfassung gibt es Links zu einzelnen Lösungen. Diese Kapriolen meine ich, wenn es darum geht Eventhandler einzurichten und zu entfernen (addEventListener/removeEventListener). Die Diskussion enstand, nachem eine einfache Lösung im Wettbewerb zum Sieger gekrönt wurde, die aber offensichtlich viele Voraussetzungen gar nicht erfüllte. Z.B. führte sie im IE zu den sog. Memory-Leaks, was anscheinend nur umständlich zu verhindern ist.

                              Gruß, Don P

              2. Das Ziel eines JS-Entwicklers sollte immer sein, die denkbar einfachste Lösung für jedes noch so komplexe Problem zu finden.

                Die richtige, nicht die einfachste.

                Wenn ein Lösungsansatz nicht richtig ist, führt er auch nicht zu einer Lösung, bestenfalls zu einem funktionsfähigen Provisorium. Das Wort "Lösung" impliziert bereits, dass es sich um etwas "Richtiges" handelt - und für manche Probleme gibt es überhaupt keine Lösung.

                Gruß, LX

                --
                RFC 1925, Satz 6a: Es ist immer möglich, einen weiteren Umweg einzufügen.
                RFC 1925, Satz 11a: Siehe Regel 6a
              3. Das Ziel eines JS-Entwicklers sollte immer sein, die denkbar einfachste Lösung für jedes noch so komplexe Problem zu finden.
                Die richtige, nicht die einfachste.

                Addendum:
                ... Sofern  diese nicht bereits durch Patente unbrauchbar gemacht ist.

                mfg Beat

                --
                ><o(((°>           ><o(((°>
                   <°)))o><                     ><o(((°>o
                Der Valigator leibt diese Fische
            3. Hallo,

              Das Ziel eines JS-Entwicklers sollte immer sein, die denkbar einfachste Lösung für jedes noch so komplexe Problem zu finden.

              Ich habe dafür einen Konfuziu-ähnlichen Spruch kreiert:
              "Das Geniale ist immer einfach. Das Komplizierte ist nie genial." [TM]

              var l = document.links.lenght;

              while (l--) { if (...) { this.init(document.links[l]); } }

                
              Es geht aber noch einfacher:  
                
              ~~~javascript
              var aTags = document.links;  
              while (aTags[0]) { (/.mp3$/i).test(aTags[0]) && this.init(aTags[0]); }
              

              Das erspart den Zähler.

              Gruß, Don P

              1. Hallo,

                Es geht aber noch einfacher:

                var aTags = document.links;

                while (aTags[0]) { (/.mp3$/i).test(aTags[0]) && this.init(aTags[0]); }

                  
                Wieder Denkfehler meinerseits :(  
                Das wird zur Endlosschleife werden wenn der Test auf .mp3 fehlschlägt.  
                Jetzt höre ich lieber auf mit meinen Tipps. Ist wohl nicht mein Tag heute.  
                  
                Gruß, Don P  
                
                
      3. Hallo,

        Mein Problem ist damit aber leider nicht gelöst.
        Die Links sind da, wenn das Script ausgeführt wird. Während der Ausführung ändert aber das Script das aTags-Array (weil es ja a-Elemente löscht/ersetzt) und es kann dann nicht mehr auf alle Elemente zugreifen.

        Achso, die Links ändern sich nicht irgendwie von außen, sondern dein Script ändert nur das Array wegen der Ersetzungen. Kann mir nicht vorstellen, dass das ein Problem sein sollte. Wenn ein a-Element, das im Array referenziert wird, nach der Ersetzung nicht mehr existiert, sollte das doch nicht stören. Du bist ja dann fertig mit ihm. Das Array-Element selber sollte aber noch existieren (d.h. aTags.length müsste doch unverändert bleiben), wenn auch aTags[i] nach der Ersetzung vielleicht undefined oder null wird.

        Jedesmal das aTags-Array neu aufzubauen ist wohl nicht wirklich performant?

        Nicht unbedingt. Aber ist ja auch ganz schön fies, wenn einem die Links unter der Hand willkürlich mutieren...

        BTW: Musik auf Webseiten abzuspielen kann Probleme mit dem Urheberrecht mit sich bringen. Die GEMA z.B. ist das sehr restriktiv und ihre Lizenzen sind ziemlich teuer...

        Gruß, Don P

        1. BTW: Musik auf Webseiten abzuspielen kann Probleme mit dem Urheberrecht mit sich bringen. Die GEMA z.B. ist das sehr restriktiv und ihre Lizenzen sind ziemlich teuer...

          Nicht alle Musik ist GEMA-pflichtig. Meine beispielsweise steht unter CC-Lizenz.

          Gruß, LX

          --
          RFC 1925, Satz 6a: Es ist immer möglich, einen weiteren Umweg einzufügen.
          RFC 1925, Satz 11a: Siehe Regel 6a
          1. Hallo,

            Nicht alle Musik ist GEMA-pflichtig.

            Ich weiß, deshalb schrieb ich "die GEMA z.B.". Das Problem bei der GEMA ist, dass es so gut wie unmöglich ist mit Sicherheit hersuzufinden, ob ein Stück bei der GEMA regisriert ist oder nicht. Der Laden ist extrem undurchsichtig :(

            Gruß, Don P

            1. Hi

              GEMA nicht, aber SUISA, da hier Schweiz.
              Aber danke für den Hinweis, muss das mal mit dem Auftraggeber diskutieren.

              PS: SUISA ist auch undurchschaubar. Sicher ist nur: man muss bezahlen.
              :-(

              1. Hallo,

                GEMA nicht, aber SUISA, da hier Schweiz.

                Achso, hier eigentlich auch :-)

                Aber danke für den Hinweis, muss das mal mit dem Auftraggeber diskutieren.

                Aber erst, nachdem er deine Arbeit bezahlt hat, oder? ;-)

                Gruß, Don P

        2. Hi,

          Die Links sind da, wenn das Script ausgeführt wird. Während der Ausführung ändert aber das Script das aTags-Array (weil es ja a-Elemente löscht/ersetzt) und es kann dann nicht mehr auf alle Elemente zugreifen.

          Achso, die Links ändern sich nicht irgendwie von außen, sondern dein Script ändert nur das Array wegen der Ersetzungen.

          Das Array ist kein Array, sondern eine NodeList.

          NodeList and NamedNodeMap objects in the DOM are live; that is, changes to the underlying document structure are reflected in all relevant NodeList and NamedNodeMap objects. For example, if a DOM user gets a NodeList object containing the children of an Element, then subsequently adds more children to that element (or removes children, or modifies them), those changes are automatically reflected in the NodeList, without further action on the user's part.”

          Kann mir nicht vorstellen, dass das ein Problem sein sollte. Wenn ein a-Element, das im Array referenziert wird, nach der Ersetzung nicht mehr existiert, sollte das doch nicht stören. Du bist ja dann fertig mit ihm. Das Array-Element selber sollte aber noch existieren (d.h. aTags.length müsste doch unverändert bleiben), wenn auch aTags[i] nach der Ersetzung vielleicht undefined oder null wird.

          Eben nicht - weil es sich *nicht* um ein Array handelt.

          Jedesmal das aTags-Array neu aufzubauen ist wohl nicht wirklich performant?

          Nicht unbedingt. Aber ist ja auch ganz schön fies, wenn einem die Links unter der Hand willkürlich mutieren...

          Nicht „willkürlich”, sondern wie in der Spezifikation festgelegt.

          Das ist übrigens auch ein Problem, welches Ansätze wie „wenn getElementsByClassName nicht nativ implementiert ist, dann erweitere ich prototyp(e-)isch HTMLElement-Objekte eben um meine eigene Methode, die ein Array mit allen betreffenden Elementen zurückliefert” haben.
          Das geht gut, so lange man diese nur so benutzt, dass die Eigenschaft echter NodeLists, „live” zu sein, gar nicht zum tragen kommt.
          Wenn man sich aber auf dieses Feature verlässt - und es gibt genügend Anwendungsfälle, in denen das sinnvoll sein kann - dann fällt man mit der selbstgebastelten Methode schnell auf die Nase (insb. dann, wenn man in Browsern, die es nativ implementiert haben, das native nutzt); oder man muss sie eben wirklich bei jedem Zugriff erneut aufrufen, damit sie auch wirklich das aktuelle DOM „live” widerspiegelt, was dann in der Tat ziemlich schnell unperformant werden dürfte.

          MfG ChrisB

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

            Das Array ist kein Array, sondern eine NodeList.

            Stimmt ja, das vergesse ich immer wieder. In SELFHTML wird es leider immer als Array bezeichnet.

            NodeList and NamedNodeMap objects in the DOM are live; that is, changes to the underlying document structure are reflected in all relevant NodeList and NamedNodeMap objects. For example, if a DOM user gets a NodeList object containing the children of an Element, then subsequently adds more children to that element (or removes children, or modifies them), those changes are automatically reflected in the NodeList, without further action on the user's part.”

            Dann ist es klar. Ich habe mir eine Helferfunktion arrayOf() gebastelt, die eine solche Collection bzw. Nodelist zu einem echten Array macht und benutze sie auch meistens, weil dann gleich die nützlichen anderen Array-Funktionen wie filter, map, forEach usw. zur Verfügung stehen. Damit wäre dann auch das live-Problem gelöst, falls zum Problem werden sollte wie hier.

            Gruß, Don P

          2. Hi

            NodeList and NamedNodeMap objects in the DOM are live;

            Jetzt verstehe ich auch den Grund des Scheiterns. Ist ja nicht das erste Mal, dass ich darüber stolpere.
            Das ist ja auch wirklich nicht besonders intuitiv.

            Gruss und off
            Mathias