Question

I have a function from which I would like to return a value as a series of events whenever a button is clicked. However, I can't figure out how to retrieve the value from onreadystatechange. How can I make it so I can return vicArray[vicID]?

function selectVictim()
{
var vicString;
var vicArray;
var vicID;

var params = "url=queenofsheep.com/Sheep/victims.php";
var request = new ajaxRequest();

request.open("POST", "victims.php", true);
request.setRequestHeader("Content-Type",
                             "application/x-www-form-urlencoded");
request.setRequestHeader("Content-Length", params.length);
request.setRequestHeader("Connection", "close");

request.send(params);

request.onreadystatechange = function ()
{
    if (this.readyState == 4)
    {
        if (this.status == 200)
        {
            if (this.responseText != null )
            {
                vicString = this.responseText;
                vicArray = JSON.parse(vicString);
                vicID = Math.floor(Math.random() * (vicArray.length - 1));
            }
            else alert("Ajax error: No data received");
        }
        else alert("Ajax Error: " + this.statusText);
    }
}
alert(vicArray[vicID]);
}
Was it helpful?

Solution

You can't. Your onreadystatechange handler gets called long after the selectVictim function returns.

What you have here is, so to say, "asynchronous functions" - i.e. functions that generate their return value not immediately, but after a certain asynchronous process.

To deal with this, one has to use a callback to provide return value:

function selectVictim( callback )
{
    ...
    ...

    request.onreadystatechange = function() {
        ...
        vicArray[vicID] = ...;
        callback( vicArray[vicID] );
    }
}

Note the callback argument. Whoever calls this function, must provide another function for this argument. Then note how selectVictim calls the callback when the return value is ready.

Now wherever you call selectVictim, you must modify your code from:

function someFunc()
{
    doSomething();

    var vic = selectVictim();

    domeSomethingElseWithVictim( vic );
}

To:

function someFunc()
{
    doSomething();

    selectVictim( function( vic ) {

        domeSomethingElseWithVictim( vic );

    } );
}

Simple enough?

OTHER TIPS

I would use a callback, in which you can pass the function that runs once the response is ready.

Add callback as a param:

function selectVictim(callback)

and then:

vicString = this.responseText;
vicArray = JSON.parse(vicString);
vicID = Math.floor(Math.random() * (vicArray.length - 1));
if (callback) {
 callback(vicID);
}

When you call the function you could do this:

selectVictim(function(vicID){ 
  console.log('This is the id: ', vicID); 
});

You can also pass the function as a value if you prefer not to do it directly. Note: it gets a little tricky if you make a ton of requests and you need to preserve the order in which they were made, but there are ways to handle that.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top