SitePoint Sponsor

User Tag List

Results 1 to 2 of 2
  1. #1
    SitePoint Guru Ize's Avatar
    Join Date
    Nov 2005
    Location
    The Netherlands
    Posts
    808
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Object losing reference to itself

    Hi, I have a very peculiar problem. I'm working on a JS library and the code I'm about to show is a snippet thereof, containing AJAX functionality.
    I wanted to ensure that only one request is active at a time. In other words: calling 2 AJAX requests right after each other first loads the first, and only if that one's finished, the second one is loaded.
    I thought I came up with a pretty good system, but it turns out odd stuff is happening. The thing I did was this:

    - create an array with AJAXConnection objects. These object have a "goAhead" property, which is false by default.
    - if the AJAXConnection object is the only one in the array, set goAhead to true immediately.
    - if not, the AJAXConnection object executes a function "onConnectionDone" on the collection object, which removes the finished AJAX object from the array and sets the goAhead property of the next object to true.
    - the AJAXConnection objects poll for its own "goAhead" property to see if they may continue loading (using setTimeout).

    Now, this works fine if only one object sits in the array, but when making two AJAX calls right after each other, the moment the second object becomes the only one in the array, it loses reference to itself. The line "$('feedback').innerHTML += 'this is: ' + this + '<br>';" prints [object Object] to the screen, as expected during the first interval, but the second time (when the object has become the first object in the queue), it prints [object Window]!

    I've run out of ideas why this happens, so any pointers would be greatly appreciated.

    Thanks in advance!

    The code:

    Code Javascript:
    What.AJAX = {
    	queue: [],
    	request: function(url,method,postData,async){
    		var req = What.AJAX.makeRequestObject();
    		if (!req){
    			return false;
    		} else {
    			var ajax = new What.AJAXConnection(req,What.AJAX);
    			ajax.init (url,method,postData,async);
    			What.AJAX.queue.push(ajax);
    			if (What.AJAX.queue.length == 1 && What.AJAX.queue[0] === ajax){
    				What.AJAX.queue[0].goAhead = true;
    			}
    			return ajax;
    		}
    	},
    	onConnectionDone: function(){
    		What.AJAX.queue.shift();
    		if (What.AJAX.queue.length > 0){
    			What.AJAX.queue[0].goAhead = true;
    		}
    	},
    	makeRequestObject: function (){
    		var obj = null;
    		if (window.XMLHttpRequest){
    			obj = new XMLHttpRequest();
    		} else if (window.ActiveXObject){
    			try {
    				obj = new ActiveXObject('Msxml2.XMLHTTP');
    			} catch (e) {
    				try {
    					obj = new ActiveXObject('Microsoft.XMLHTTP');
    				} catch (e) {
    					obj = null;
    				}
    			}
    		}
    		return obj;
    	},
    	isSupported: function (){
    		return !!What.AJAX.makeRequestObject();
    	}
    };
     
    What.AJAXConnection = function (request,manager){
    	this.xhr = request;
    	this.manager = manager;
    	this.url;
    	this.method = 'GET';
    	this.postData = null;
    	this.loadInterval = null;
    	this.async = true;
    	this.goAhead = false;
    	this.response;
    	this.init = function(url,method,postData,async){
    		this.url = url;
    		this.method = method || 'GET';
    		this.postData = postData || null;
    		this.async = typeof async=='boolean'?async:true;
    		var s = this;
    		What.extend(What.AJAXConnection.prototype,What.Event.Manager);
    		this.registerEvents('onLoading','onReady','onFailure');
     
    		this.xhr.onreadystatechange = function(){
    			if (s.xhr.readyState == 4){
    				if (s.xhr.status == 200 || s.xhr.status == 304){
    					var xml = s.xhr.responseXML;
    					var text = s.xhr.responseText;
    					s.response = {xml: xml, text: text, parseJSON: function(){ return eval('('+text+')'); }};
    					s.broadcastEvent('onReady');
    					s.manager.onConnectionDone();
    				} else {
    					s.broadcastEvent('onFailure');
    				} 
    			}
    		}
    	}
    	this.load = function (){
    		$('feedback').innerHTML += 'this is: ' + this + '<br>';
    		this.broadcastEvent('onLoading');
    		if (this.loadInterval){
    			clearTimeout(this.loadInterval);
    			this.loadInterval = null;
    		}
    		if (this.goAhead){
    			this.connect();
    		} else {
    			var s = this;
    			this.loadInterval = setTimeout(s.load,30);
    		}
    	}
    	this.connect = function (){
    		this.xhr.open(this.method,this.url,this.async);
    		this.xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
    		this.xhr.send(this.postData);
    	}
    	What.extend(What.AJAXConnection.prototype,What.Event.Manager);
    	this.registerEvents('onLoading','onReady','onFailure');
    }

    Usage:

    Code Javascript:
    var a = What.AJAX.request('/data/stuff.xml','GET');
    		a.onReady=function(){
    			$('feedback').innerHTML += 'a loaded... <br>';
    		}
    		a.onFailure=function(){
    			$('feedback').innerHTML += 'a could not load... <br>';
    		}

  2. #2
    SitePoint Guru Ize's Avatar
    Join Date
    Nov 2005
    Location
    The Netherlands
    Posts
    808
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    OMG. I'm so sorry for bothering you people. I just had an epiphany; that setTimeout call is incorrect. It should be inside a closure:

    Code Javascript:
    this.loadInterval = setTimeout(function(){s.load();},30);

    To think I spent HOURS on this problem.. bah.


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •