Eigene Ajax-Klasse

Rambomaster

Mitglied
Hallo Zusammen

Ich bin momentan gerade dran mir eine eigene Ajax-Klasse zu basteln. Wie in vielen Fällen funktioniert nicht immer alles genau so wie ich es gerne hätte, deshalb frage ich hier im Forum einfach mal nach ob jemand eine andere oder bessere Idee hat um mein Problem zu lösen ;)

Mein Problem:
Ich möchte gerne von meiner handleResponse Funktion aus auf die Variablen und Funktionen der Klasse zugreifen. Mit this funktionierts ja schon mal nicht, da man ja innerhalb der handleResponse Funktion sozusagen im XmlHttpRequest Objekt ist. Leider ist es auch nicht möglich Parameter an die Callback Funktion zu übergeben.

Gibt es da eine andere oder bessere Möglichkeit um das Problem zu lösen?
@edit: Ich hab nach langer Suche im Internet endlich eine Lösung gefunden. Ich habe den Code unten mal aktualisiert.

Hier mal mein bisheriger Code:
PHP:
function AjaxRequest() {
	var self = this;
	var xmlHttpRequest = null;
	var timeout = null;
	
	/**
	* Sendet einen Ajax Request.
	* 
	* @param	method		GET/POST
	* @param	url			An diese URL wird der Request gesendet
	* @param	params		Diese Parameter werden mit dem Request mitgesendet
	* @param	async		true/false
	* @param	timeout		in ms
	* @param	type		Rückgabeformat: html, text, xml, json
	* @param	callback	Callback-Funktion
	*/
	this.sendRequest = function(method, url, params, async, timeout, type, callback) {
		this.timeout = timeout;
		
		if(this.openXMLHttpRequest()) {
			if(method == "GET") {
				this.xmlHttpRequest.open(method, url + "?" + params, async);
				this.xmlHttpRequest.send(null);
				return true;
			} else if(method == "POST") {
				this.xmlHttpRequest.open(method, url, async);
				this.xmlHttpRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
				this.xmlHttpRequest.send(params);
				return true;
			} else {
				alert("Unknown method!");
				return false;
			}
		}
		return false;
	}
	
	this.openXMLHttpRequest = function() {
		if(this.xmlHttpRequest) {
			if(this.xmlHttpRequest.readyState != 0 && this.xmlHttpRequest.readyState != 4) {
				return false;
			}
			
			this.xmlHttpRequest.abort();
		}
		
		try {
			// Mozilla, Opera und Safari
			this.xmlHttpRequest = new XMLHttpRequest();
		} catch(e) {
			// Internet Explorer
			try {
				this.xmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP");
			} catch(e) {
				try {
					this.xmlHttpRequest = new ActiveXObject("Microsoft.XMLHTTP");
				} catch(e) {
					alert("Your browser does not support AJAX!");
					return false;
				}
			}
		}
		
		
		this.xmlHttpRequest.onreadystatechange = this.handleResponse;
		
		return true;
	}
	
	this.handleResponse = function() {
		if(this.readyState == 1) {
			if(self.timeout != null) {
				
			}
		}
		
		if(this.readyState == 4) {
			if(this.status != 200) {
				// Es ist ein Fehler aufgetreten
				alert("Error: " + this.status + " - " + this.statusText);
			} else {
				// Alles OK
				document.getElementById('debug').innerHTML = this.getResponseHeader("Content-Type") + ": " + this.responseText;
			}
		}
	}
}

Nun kommt aber schon mein nächstes Problem ;)
Und zwar will ich, dass man ein Timeout angeben kann, damit der Request einfach nach einer gewissen Zeit abgebrochen wird.
Wie könnte man das lösen?
Ich habs schon mit einem setTimeout versucht, aber das führte wieder an Probleme, da ich wieder keine Funktion der Klasse aufrufen kann.
 
Zuletzt bearbeitet:
Hallo Zusammen

Und zwar will ich, dass man ein Timeout angeben kann, damit der Request einfach nach einer gewissen Zeit abgebrochen wird.
Wie könnte man das lösen?
Ich habs schon mit einem setTimeout versucht, aber das führte wieder an Probleme, da ich wieder keine Funktion der Klasse aufrufen kann.

Schicke doch einfach einen Timestamp mit und vergleiche den mit dem aktuellen nach den request und baue dir dazu eine Funktion mit einen Timeout.

Gruss

ich meinte so vielleicht
Code:
function getInfo(){

var curDateTime = new Date();
http[curDateTime] = createRequestObject();

http[curDateTime].open('get', '/responses/responses.php');

http[curDateTime].onreadystatechange = function(){
	if (http[curDateTime].readyState == 4) 
   	{
       	if (http[curDateTime].status == 200 || http[curDateTime].status == 304) 
       	{
          	 	var response = http[curDateTime].responseText;
				document.getElementById('blabla').innerHTML = response;
		
       	}
   	}
}

http[curDateTime].send(null);
}
 
Zuletzt bearbeitet von einem Moderator:
Mein Problem ist eher, wie mache ich eine Funktion in meiner Klasse, die sich etwa gleich verhält wie die setTimeout Funktion. Dieser Timeout sollte asynchron laufen. Ich habe schon versucht eine eigene Timeout-Funktion zu bauen, die hat aber den kompletten Browser lahm gelegt :rolleyes:
 
Hi,

zunächst wäre es schön gewesen, wenn du eine wirklich funktionierende Version deines Scripts gepostet hättest. Denn Zugriff auf das XMLHttpRequest-Objekt hast in der Methode handleRequest nicht über das Schlüsselwort this sondern über self.xmlHttpRequest.

Um ein Timeout zu realisieren, könntest du das Stoppen des Requests nach dem Senden (send-Methode) zeitverzögert anstossen. Wird nach abgelaufener Zeit festgestellt, dass der Request noch nicht abgeschlossen, wird er angehalten.

Beispiel:
Code:
function AjaxRequest() {
    var self = this;
    var xmlHttpRequest = null;
    var timeout = null;

    this.hTimer = null;

    /**
    * Sendet einen Ajax Request.
    *
    * @param    method        GET/POST
    * @param    url            An diese URL wird der Request gesendet
    * @param    params        Diese Parameter werden mit dem Request mitgesendet
    * @param    async        true/false
    * @param    timeout        in ms
    * @param    type        Rückgabeformat: html, text, xml, json
    * @param    callback    Callback-Funktion
    */
    this.sendRequest = function(method, url, params, async, timeout, type, callback) {
        this.timeout = timeout;

        if(this.openXMLHttpRequest()) {
            if(method == "GET") {
                this.xmlHttpRequest.open(method, url + "?" + params, async);
                this.xmlHttpRequest.send(null);
          	this.startTimeout();
                return true;
            } else if(method == "POST") {
                this.xmlHttpRequest.open(method, url, async);
                this.xmlHttpRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
                this.xmlHttpRequest.send(params);
          	this.startTimeout();
                return true;
            } else {
                alert("Unknown method!");
                return false;
            }
        }
        return false;
    }


    this.startTimeout = function(){
      // Falls bereits ein Timeout läuft -> beenden
      if(this.hTimer != null){
        window.clearTimeout(this.hTimer);
        this.hTimer = null;
      }

      // Timeout starten
      this.hTimer = window.setTimeout(
        function(){
          // Falls noch ein Request ausgeführt wird
          if(self.xmlHttpRequest && (self.xmlHttpRequest.readyState!=0) && (self.xmlHttpRequest.readyState!=4)){
            self.xmlHttpRequest.onreadystatechange = function(){}
            self.xmlHttpRequest.abort();
            self.xmlHttpRequest = false;
            delete self.xmlHttpRequest;
            self.hTimer = null;
            document.getElementById('debug').innerHTML = "Request abgebrochen";
          }
        },
        self.timeout
      );
    }

    this.openXMLHttpRequest = function() {
        if(this.xmlHttpRequest) {
            if(this.xmlHttpRequest.readyState != 0 && this.xmlHttpRequest.readyState != 4) {
                return false;
            }

            this.xmlHttpRequest.abort();
        }

        try {
            // Mozilla, Opera und Safari
            this.xmlHttpRequest = new XMLHttpRequest();
        } catch(e) {
            // Internet Explorer
            try {
                this.xmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP");
            } catch(e) {
                try {
                    this.xmlHttpRequest = new ActiveXObject("Microsoft.XMLHTTP");
                } catch(e) {
                    alert("Your browser does not support AJAX!");
                    return false;
                }
            }
        }


        this.xmlHttpRequest.onreadystatechange = this.handleResponse;

        return true;
    }

    this.handleResponse = function() {
        if(self.xmlHttpRequest.readyState == 1) {
            if(self.timeout != null) {

            }
        }

        if(self.xmlHttpRequest.readyState == 4) {
            if(self.xmlHttpRequest.status != 200) {
                // Es ist ein Fehler aufgetreten
                alert("Error: " + self.xmlHttpRequest.self.xmlHttpRequest + " - " + this.statusText);
            } else {
	       if(self.hTimer != null){
	            window.clearTimeout(self.hTimer);
	            self.hTimer = null;
	       }

                // Alles OK
                document.getElementById('debug').innerHTML = self.xmlHttpRequest.getResponseHeader("Content-Type") + ": " + self.xmlHttpRequest.responseText;
            }
        }
    }
}
Vielleicht kannst du damit etwas anfangen.

Ciao
Quaese
 
Danke erst mal für den Lösungsvorschlag ich werd mir den mal genauer unter die Lupe nehmen ;)

Klar funktioniert das mit this in der handleResponse Funktion. Das ist ja genau der sinn von der Callback-Funktion. Ich habe mittlerweile auch ein bisschen weiter rum probiert und bin auch auf eine Lösung gekommen. Es gibt irgendwie noch ein Problem nachdem der Request abgebrochen wurde springt er ins if(this.readyState == 4) kann dann aber den alert nicht richtig ausgeben, keine Ahnung warum.

Hier der aktuellste Code:
PHP:
/*
Guter Link: http://www.drweb.de/programmierung/ajax-xmlhttpRequest.shtml
*/

function AjaxRequest() {
	var self = this;
	var xmlHttpRequest = null;
	var timeout = null;
	
	/**
	* Sendet einen Ajax Request.
	* 
	* @param	method		GET/POST
	* @param	url			An diese URL wird der Request gesendet
	* @param	params		Diese Parameter werden mit dem Request mitgesendet
	* @param	async		true/false
	* @param	timeout		in ms
	* @param	type		Rückgabeformat: html, text, xml, json
	* @param	callback	Callback-Funktion
	*/
	this.sendRequest = function(method, url, params, async, timeout, type, callback) {
		this.timeout = timeout;
		
		if(this.openXMLHttpRequest()) {
			if(method == "GET") {
				this.xmlHttpRequest.open(method, url + "?" + params, async);
				this.xmlHttpRequest.send(null);
				return true;
			} else if(method == "POST") {
				this.xmlHttpRequest.open(method, url, async);
				this.xmlHttpRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
				this.xmlHttpRequest.send(params);
				return true;
			} else {
				alert("Unknown method!");
				return false;
			}
		}
		return false;
	}
	
	this.openXMLHttpRequest = function() {
		if(this.xmlHttpRequest) {
			if(this.xmlHttpRequest.readyState != 0 && this.xmlHttpRequest.readyState != 4) {
				return false;
			}
			
			this.xmlHttpRequest.abort();
		}
		
		try {
			// Mozilla, Opera und Safari
			this.xmlHttpRequest = new XMLHttpRequest();
		} catch(e) {
			// Internet Explorer
			try {
				this.xmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP");
			} catch(e) {
				try {
					this.xmlHttpRequest = new ActiveXObject("Microsoft.XMLHTTP");
				} catch(e) {
					alert("Your browser does not support AJAX!");
					return false;
				}
			}
		}
		
		
		this.xmlHttpRequest.onreadystatechange = this.handleResponse;
		
		return true;
	}
	
	this.handleResponse = function() {
		//document.getElementById('debug').innerHTML = "Ready State: " + self.xmlHttpRequest.readyState + ", Status: " + self.xmlHttpRequest.status + ", Status Text: " + self.xmlHttpRequest.statusText;
		
		if(this.readyState == 1) {
			if(self.timeout != null) {
				window.setTimeout(function() {
					self.xmlHttpRequest.abort();
				}, self.timeout);
			}
		}
		
		if(this.readyState == 4) {
			if(this.status != 200) {
				// Es ist ein Fehler aufgetreten
				alert("Error: " + this.status + " - " + this.statusText);
			} else {
				// Alles OK
				document.getElementById('debug').innerHTML = this.getResponseHeader("Content-Type") + ": " + this.responseText;
			}
		}
	}
}
 
Hi,

ich weiss ja nicht, wie dein Dokument aussieht und wo du testest, aber bei mir funktioniert die Callback-Funktion nicht. Es gibt zwar keinen Fehler, aber aufgrund der nicht vorhandenen Eigenschaften (readyState, status usw) wird auch nichts bearbeitet.

Selbst wenn this in der Methode responseHandler auf eine Instanz von AjaxRequest zeigte, müsste über die Eigenschaft xmlHttpRequest auf die erforderlichen Attribute (readyState, status usw.) zugegriffen werden.

this zeigt jedoch auf andere Objekte. Im IE auf das window-Objekt, im FF auf die Funktion (handleResponse) selbst. Du kannst dir ja in handleResponse mal ausgeben lassen, welche Inhalte this besitzt.
Code:
var strOut = "";
for(var strEntry in this){
  strOut += "this["+strEntry+"] = " + this[strEntry] + " ("+(typeof this[strEntry])+")" + "<br>";
}
document.getElementById('debug').innerHTML = strOut + "<br>this.toString: " + this.toString();

Um über this auf eine Instanz von AjaxRequest zugreifen zu können, muss schon der Aufruf der Callback-Funktion im Kontext der Instanz erfolgen. Das erfolgt über eine anonyme Funktion.
Code:
this.xmlHttpRequest.onreadystatechange = function(){
  self.handleResponse();
}
Wird die Callback-Funktion so aufgerufen, kann in ihr über this und seine Eigenschaft xmlHttpRequest auf das gewünschte Request-Objekt und damit auf die erforderlichen Attribute (readyState, status usw) zugegriffen werden.

Weiterhin würde ich "self" als Variablenname nicht verwenden, da es eine Referenz auf das window-Objekt mit gleichem Name gibt.

Sollte ich mit meinen Ausführen völlig daneben liegen, lasse ich mich gerne eines Besseren belehren.

Ciao
Quaese
 
Ich teste hier mit einem XAMPP Server (wobei der nichts mit Javascript zu tun hat) und Firefox 3.0.1. Zum testen verwende ich Firebug 1.2.1b1.

In der Firebug-Konsole führe ich folgender Code aus:
PHP:
ajaxRequest.sendRequest("GET", "ajax.php", "msg=sleep", true, 3000, "xml");

Ich habe im Firebug einen Breakpoint gesetzt und da sieht man deutlich, dass this innerhalb der Callback-Funktion "handleResponse" auf das XMLHttpRequest Objekt zeigt.

Hier ein Screenshot:
http://img253.imageshack.us/img253/8351/ajaxdr0.png

Den Variablenname "self" habe ich desshalb gewählt, weil ich schon des öfteren in Javascript-Libraries gesehen habe, wie damit gearbeitet wurde.


Im Anhang habe ich mal alle meine Dateien ran gehängt die so bei mir Funktionieren, bis auf einen kleinen Fehler den ich irgendwie nicht ganz nachvollziehen kann.

Hier ein Screenshot der Firebug Konsole:
http://img300.imageshack.us/img300/175/ajaxfehlerxr5.png
 

Anhänge

Hi,

angesehen hab ich mir dein Konstrukt - funktioniert hat es bei mir allerdings nicht.

Der Firebug zeigt mir in handleResponse für this kein XMLHttpRequest-Objekt an.

Führe ich die Änderungen durch wie in meinen vorherigen Beiträgen beschrieben, bekomme ich die erwartete Rückmeldung vom PHP-Script angezeigt (die if-Bedingung mit der Timeout-Anweisung habe ich auskommentiert).

Mehr kann ich zu dem Thema nicht mehr sagen.

Ciao
Quaese
 
So inzwischen habe ich eigentlich alle meine Probleme beseitigt und habe zusätzlich noch einiges an der Klasse geändert.

@Quaese Ich habe keine Ahnung wo das Problem bei dir liegt. Ich habe extra die Klasse noch einem Kollegen geschickt und bei dem lief wie bei mir alles normal durch. So wie es bei mir läuft ist es glaube ich auch vorgesehen. Ich hab in vielen Tutorials gesehen, wie mit this in der Callback-Funktion direkt auf das XMLHttpRequest-Objekt zugegriffen wurde. Aber trotzdem danke für deine Hilfe, du hast mir doch den ein oder anderen Gedankenanstoss gegeben :)

Im Anhang habe ich nochmal das komplette Packet mit allen Testdaten rangehängt. So wie es dort ist, läuft es bei mir. Wenn ihr einen Bug findet bitte melden :rolleyes:
 

Anhänge

Hi,

ok, es läuft im FF 3, IE 7, Safari 3 und Opera - aber nicht im IE6 und kleiner, FF2 und kleiner, Seamonkey 1.1.7, Netscape 7.1 und Mozilla 1.7 (evtl auch noch andere).

Warum es in den Erstgenannten läuft - keine Ahnung. Vielleicht hat jemand eine Erklärung dafür. Würde mich auch interessieren.
Edit:
Für mich nur erklärbar, dass die Funktion beim Aufruf der Callback-Funktion im Kontext des Event-Objekts, also des XMLHttpRequest-Objekts, läuft. Würde auch für @rambomasters Argumentation sprechen. Aber hätten es dann die oben zweitgenannten Browser bisher nicht falsch interpretiert?

Mit den von mir erwähnten Änderungen funktioniert die Klasse in allen oben genannten Browsern.

Ciao
Quaese
 

Neue Beiträge

Zurück