nam: XHR funktioniert nicht in Opera

Hallo

Folgendes Problem:
Ich will JavaScript-Dateien dynamisch zuladen, wenn diese gebraucht werden und vorher mittels eines vorgängigen, synchronen XMLHttpRequests eine 404-Fehler abfangen:

function loadScript(url) {  
	//check if 'url' is available:  
	var xhr = null;  
	if (typeof XMLHttpRequest != 'undefined') {  
		xhr = new XMLHttpRequest();  
	}  
	if (!xhr) {  
		try {  
			xhr  = new ActiveXObject("Msxml2.XMLHTTP");  
		} catch(e) {  
			xhr  = null;  
		}  
	}  
	if (xhr) {  
		xhr.open('HEAD', url, false);  
		xhr.send();  
		if(xhr.status == 404) {  
			alert('Could not load\n'+url);  
			return;  
		}  
	}  
	var head = document.getElementsByTagName('head').item(0);  
	var script = document.createElement('script');  
	script.src = url;  
	script.type = 'text/javascript';  
	head.appendChild(script);  
}  
loadScript('script1.js');  

Funktioniert alles tiptop allen getesteten Browsern, ausser in Opera (9.60).
Dieser bleibt hängen und führt 'script1.js' nicht aus.

Wenn man allerdings den Ladevorgang abbricht und nachher auf reload clickt, funktioniert es manchmal...

Hat jemand eine Idee, woran das liegt bzw. ob/wo ich einen Fehler gemacht habe?

Danke für die Antworten,
nam

  1. @@nam:

    […] ausser in Opera (9.60).

    Update!

    Live long and prosper,
    Gunnar

    --
    Das einzige Mittel, den Irrtum zu vermeiden, ist die Unwissenheit. (Jean-Jacques Rousseau)
  2. Bevor ich da lange rumsuchen würde: Versuche es mit einem asynchronen Request. Ich sehe hier keine Notwendigkeit für einen synchronen.

    Mathias

    1. Hi Mathias

      Tja, auch das hilft nicht (falls ich alles richtig gemacht habe:)

      function loadScript(url) {  
      	//check if 'url' is available:  
      	var xhr = null;  
      	function processReqChange() {  
      		// only if req shows "loaded"  
      		if (xhr.readyState == 4) {  
      			// only if "OK"  
      			if (xhr.status == 200) {  
      				var head = document.getElementsByTagName('head').item(0);  
      				var script = document.createElement('script');  
      				script.src = url;  
      				script.type = 'text/javascript';  
      				head.appendChild(script);  
      			} else {  
      				alert("There was a problem retrieving the XML data:\n" +  
      					xhr.statusText);  
      			}  
      		}  
      	}  
      	if (typeof XMLHttpRequest != 'undefined') {  
      		xhr = new XMLHttpRequest();  
      	}  
      	if (!xhr) {  
      		try {  
      			xhr  = new ActiveXObject("Msxml2.XMLHTTP");  
      		} catch(e) {  
      			xhr  = null;  
      		}  
      	}  
      	if (xhr) {  
      		xhr.onreadystatechange = processReqChange;  
      		xhr.open('HEAD', url, true);  
      		xhr.send(null);  
      	}  
      }  
      loadScript('script1.js');  
      
      

      Siehe hier : http://mnn.ch/diversa/opera/opera.html

      1. Vermutlich liegts am HEAD statt GET und Opera ist dafür einfach nicht ausgelegt.
        Prüfe mal, ob der readystate-Handler überhaupt gefeuert wird und wie der readyState und status dann ist.

        Mathias

        1. Hi

          Prüfe mal, ob der readystate-Handler überhaupt gefeuert wird und wie der readyState und status dann ist.

          Funktioniert alles tiptop. Habe ein paar opera.postError-Statements eingefügt. Siehe http://mnn.ch/diversa/opera/opera.html

          Es werden readyState 1-4 durchlaufen, getAllResponseHeaders() liefert dasselbe wie in anderen Browsern und der Status am Schluss ist 200.

          Die Einbindung danach funktioniert nicht (nur wenn ich den xhr davor auskommentiere).

          Es scheint also, dass das ein Bug in Opera ist...
          Habe einfach mal ein Bugreport gemacht.

          Gruss,
          nam

          1. Jipeee!
            Ich hab's gefunden!

            Die Einbindung danach funktioniert nicht (nur wenn ich den xhr davor auskommentiere).

            Das Problem war offenbar der Cache in Opera. Wahrscheinlich wird da der HEAD-Request im Cache gespeichert - natürlich ohne Inhalte - und Opera versucht dann danach wieder auf den Cache zuzugreifen und das Script von da zu laden. Da aber keine Inhalte da sind, gehts nicht.

            Wenn ich im XMLHttpRequest auf no-cache schalte klappts.

            function loadScript(url) {  
            	//check if 'url' is available:  
            	var xhr = null;  
            	function processReqChange() {  
            		if (window.opera) { opera.postError(xhr.readyState); }  
            		// only if req shows "loaded"  
            		if (xhr.readyState == 4) {  
            			if (window.opera) { opera.postError(xhr.getAllResponseHeaders()); }  
            			if (window.opera) { opera.postError(xhr.status); }  
            			// only if "OK"  
            			if (xhr.status == 200) {  
            				var head = document.getElementsByTagName('head').item(0);  
            				var script = document.createElement('script');  
            				script.src = url;  
            				script.type = 'text/javascript';  
            				head.appendChild(script);  
            			} else {  
            				alert("There was a problem retrieving the XML data:\n" +  
            					xhr.statusText);  
            			}  
            		}  
            	}  
            	if (typeof XMLHttpRequest != 'undefined') {  
            		xhr = new XMLHttpRequest();  
            	}  
            	if (!xhr) {  
            		try {  
            			xhr  = new ActiveXObject("Msxml2.XMLHTTP");  
            		} catch(e) {  
            			xhr  = null;  
            		}  
            	}  
            	if (xhr) {  
            		xhr.onreadystatechange = processReqChange;  
            		xhr.open('HEAD', url, true);  
            		xhr.setRequestHeader('Cache-Control','no-cache');  
            		xhr.send(null);  
            	}  
            }  
            loadScript('script1.js');
            

            Siehe hier: http://mnn.ch/diversa/opera/opera_fix.html

            Gruss,
            Mathias

  3. Hi,

    Ich will JavaScript-Dateien dynamisch zuladen, wenn diese gebraucht werden und vorher mittels eines vorgängigen, synchronen XMLHttpRequests eine 404-Fehler abfangen:

    Wozu? Nur um dem Nutzer die Rueckmeldung zu geben, dass das Script nicht gefunden werden konnte?

    Denn wenn eine vernuenftige 404-Antwort erfolgt, macht das in keinem mir bekannten Browser Probleme, wenn man versucht hat eine nicht existente JS-Ressource per Script einzubinden.

    Wenn eine "normal", nicht auf diese Weise dynamisch eingebundene Script-Ressource nicht geladen werden konnte - dann erfolgt darauf doch i.a.R. auch keine zusaetzliche (fehlerbehandelnde) Reaktion - also wozu gerade hier?

    MfG ChrisB

    --
    „This is the author's opinion, not necessarily that of Starbucks.“
    1. Hallo ChrisB

      Wozu?

      Das sei hier nicht der zur Debatte gestellt.

      Gruss,
      Mathias

  4. Übrigens definiert HTML 5, dass script-Elemente load- und error-Events feuern. Dummerweise wird nur load bisher in den großen Browsern unterstützt.

    Mathias