SitePoint Sponsor

User Tag List

Results 1 to 7 of 7
  1. #1
    SitePoint Member
    Join Date
    Nov 2007
    Posts
    3
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Thumbs down Javascript "objects" and asynchronous methods

    Hello everyone,

    I came accross this unbelieveably stupid thing in javascript that has been driving me mad in the last few hours. I'd like to share my problem with you, i have very little experience in OO javascript and this might just be the root cause of all my troubles .. :-)

    So i've been trying to put together a javascript class to grab some JSON from my php app, table-ize the data and display it. Just as i completed this task in a non-OO (procedural) manner, i realized if i wont convert my functions to a class, the multi-million dimension arraying will drive me crazy when it'll come to rendering another table on the same page, with different data (different request, different JSON response).

    i set up my class, defining properties and methods:

    Code:
    function magicClass(name) {
    
    	this.myName = name
    	this.someVar1 = ''
    	this.someVar2 = ''
    
    	this.function asyncFunction() {
    		// i'm using my class-properties here and after asynchronous http requests 
    	}
    
    }
    I went ahead to test my class, using it on 2 locations on a single page.

    Code:
    classone = new magicClass('one')
    classone.someVar1 = 'var1_in_class_one'
    
    classtwo = new magicClass('two')
    classtwo.someVar1 = 'var1_in_class_two'
    i even double checked to see if someVar1 was different in classone and classtwo.. it was and i was amazed.. :-)

    It was time to move on..

    Code:
    classone = new magicClass('one')
    classone.someVar1 = 'var1_in_class_one'
    classone.asyncFunction() // gets JSON, updates DOM (according to 'name')
    
    classtwo = new magicClass('two')
    classtwo.someVar1 = 'var1_in_class_two'
    classtwo.asyncFunction() // gets JSON, updates DOM (according to 'name')
    My amazement didnt last long though. As you can "see" i'm doing asynchronous calls in a method (a function of the object) to fetch my JSON. I'm relying on my class-variables (properties) to update the DOM after the AJAX call. This is where OO javascript came crashing down on me.. asyncFunction() fires on the "instances" (notice the quotes..) almost immediately, with the first one finishing first, the second later. All makes sense, right? Now the problem is, by the time the async method on my "firstly" initiated class finishes, it "sees" the second instance's data.. in other words, classone.someVar1 has classtwo.someVar1 's value ..

    how the HELL is this possible..? :-(

    Thanks...
    Andrew

  2. #2
    SitePoint Wizard chris_fuel's Avatar
    Join Date
    May 2006
    Location
    Ventura, CA
    Posts
    2,750
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    http requests and class objects are a tricky endeavor. What happens is that when a function is set as the request handler, the function's "this" will be set to the http request object, not the class.

    What I've done before is to set the class object as a property of the http object, which allows me to use that property to access the object's internal functions and variables.

  3. #3
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Create a closure. Instead of this:
    Code:
    http.onComplete(classone.asyncFunction);
    Do this:
    Code:
    http.onComplete(function() {
      classone.asyncFunction();
    });

  4. #4
    SitePoint Member
    Join Date
    Nov 2007
    Posts
    3
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks for the replies.

    kyberfabrikken, i think i've been doing that..
    This is my async function

    Code:
    	this.getQueue = function() {
    		this.qDestroy() // i'm removing the previous queue from the DOM
    		this.qKickLoading('start') // i'm starting a loading gif :-) very web2.0
    		a = this; // i need this to be able to access a method of the class from within the closure
    		new Ajax.Request('/url/'+this.qType+'/'+this.qDate+'/'+this.qSubject+'/'+this.qFilter+'/'+this.qPage, {
    			method:'get',
    			onSuccess: function(transport) {
    				myqueue = transport.responseText.evalJSON();
    				a.evalQueue(myqueue) // this is the method that parses my JSON and updates the DOM
    			}, asynchronous: true
    			}
    		);
    	}
    if i set "asynchronous" to "false", everything works great. It just horribly bogs down the page and defeats the very purpose of AJAX.

    Also, as you can see, i'm using prototype to do the call.

    thanks for all your help.

    edit: do you think i should seperate the fetching of data and the processing? Take the http request outside the class?

  5. #5
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Code:
    a = this; // i need this to be able to access a method of the class from within the closure
    Variables are implicitly global, unless you declare them local. You need to change that line to:
    Code:
    var a = this; // i need this to be able to access a method of the class from within the closure
    Otherwise, you're overriding the same variable each time, you call this.getQueue()

  6. #6
    SitePoint Member
    Join Date
    Nov 2007
    Posts
    3
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    err.. so what do you drink?? :-)

    i was totally unaware of that. Thanks. It fixed everything of course. I even had to declare my incremental variables in for loops - before i realized this i've spent a good 15 minutes trying to figure out the seemingly random behaviour.

    One question to close this thread: Does data isolation by the means of creating instances of the same class work fine in javascript? The unwanted "race condition" i described was only a result of my variables not being explicitly declared as local, right?

  7. #7
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by pgn View Post
    err.. so what do you drink?? :-)
    You're welcome to buy me a beer, if you stop by Copenhagen.

    Quote Originally Posted by pgn View Post
    i was totally unaware of that. Thanks. It fixed everything of course. I even had to declare my incremental variables in for loops - before i realized this i've spent a good 15 minutes trying to figure out the seemingly random behaviour.
    Yeah, it's not the most intuitive aspect of Javascript.

    Quote Originally Posted by pgn View Post
    One question to close this thread: Does data isolation by the means of creating instances of the same class work fine in javascript? The unwanted "race condition" i described was only a result of my variables not being explicitly declared as local, right?
    Yes, exactly. If you call a function twice, the var keyword will create two separate variables -- just like in most other languages. It's just that if you don't declare a variable explicitly, it's assumed that you refer to a global variable.


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
  •