views:

146

answers:

3

I'm using global variables to pass around a response from a AJAX call:

window.response = null; // most recent response from XMLHttpRequest

// the callback function for XMLHttpRequest
function userObjFromJSON() {
    if (this.readyState == 4) {
        var json = eval('(' + this.responseText + ')');
        window.response = json;
    }
    else {
        indicateLoading();
    }
}

// loads the info for this username on the page
function loadUsernameInfo(username) {
    clearPage();
    getUserInfo(username);
    var profile = window.response; // most recent json response (what if it hasn't come in yet?)
    window.response = null;
    if (profile) {
        indicateLoaded(username);
        fillInProfileInfo(profile);

        getTweets(username);
        var tweets = window.response; // most recent json response (what if it hasn't come in yet?)
        if (tweets) {
            fillInTweets(tweets, MAX_TWEETS);
            var mentions = mentionedUsers(tweets, MAX_TWEETS);
            fillInMentioned(mentions);
        }
        else {
            indicateUnavailableTweets();
        }
    }
    else {
        indicateInvalidUsername(username);
    }
}

The problem is that, by the time the controller function wants to start filling in information, the AJAX call hasn't always returned yet. (If I step through it slowly in a debugger, it works fine.) What can I do to get around this?

I tried something like this:

getUserInfo(username);
while (window.response == null); // infinite loop here
var profile = window.response; // most recent json response

But that just makes my browser unresponsive.

I am hesitant to call the needed function from the callback, because I'm trying to implement model-view-controller. Calling a controller/view function from the model feels like it would break the pattern.

A: 
function userObjFromJSON() {
if (this.readyState == 4) {
    var json = eval('(' + this.responseText + ')');
    window.response = json;
// why dont you call needed function here ?
}
else {
    indicateLoading();
}

}

Why dont you call all needed function when you set window.response ?

In a worst way you can use window.setTimeout to wait for the ajax reply but the best way is to use events.

RafH
+1  A: 

The best practice here would be to place the code you currently have in loadUsernameInfo into the callback for the AJAX call itself, instead of relying on the global variable. That way, when your response comes back, the callback that executes, instead of just setting your window.response variable, will actually go ahead and update your UI and perform any other related tasks.

Another way of doing the same thing is just to call loadUsernameInfo from your existing callback, like:

// the callback function for XMLHttpRequest
function userObjFromJSON() {
    if (this.readyState == 4) {
        var profile = eval('(' + this.responseText + ')');
        loadUsernameInfo(username, profile);
    }
    else {
        indicateLoading();
    }
}

Hope that helps!

Mason Tang
A: 

Your XMLHttpRequest should be using the onreadystatechange event. for instance:

var xmlHttp=new XMLHttpRequest();
xmlHttp.onreadystatechange=function(){
    if( xmlHttp.readyState!=4 || (xmlHttp.status!=200 && xmlHttp.status!=304))return;
    callback(xmlHttp.responseText);

}

Where callback() is the function you want it to call. A readyState of 4 means that the content has finished loading. And the two status entries are to make sure that the url didn't give an error.

Chibu
I'm trying to do model-view-controller, and putting the function call there would violate that.
Rosarch