1

So, I have an init function that runs when the DOM is fully loaded:

function init() 
{
    TerrainObj.load_terrain();
    TerrainObj.generate_display_layer(PlayerObj);
    GameObj.update();
    ScreenObj.draw_screen(TerrainObj);
    ScreenObj.update_screen(TerrainObj);
    mainloop();
}

The very first method, TerrainObj.load_terrain(), makes an AJAX requestL:

load_terrain: function()
{
    var settings = {
        type: "GET",
        url: "data/map.txt",
        aysnc: false
    };

    $.ajax(settings).done(function(result) 
    {
        this.terrain = result.split("\n");
        for (var i = 0; i < this.terrain.length; i++)
        {
            this.terrain[i] = this.terrain[i].split("")
        }
        console.log(this.terrain);
    });
}

The problem is that, in our init() function, most of the methods that follow TerrainObj.load_terrain() require the presence of the TerrainObj.terrain array, but they are called before the AJAX request can complete and that variable is populated. I put a little message out when each function runs to check the order, and I get this:

Ran TerrainObj.load_terrain()
Ran ScreenObj.draw_screen()
Uncaught TypeError: Cannot read property '0' of undefined 
[Array[55], Array[55], ... ]

So as you can probably see, ScreenObj.draw_screen, which needs TerrainObj.terrain, has run before the request can complete, and there's a TypeError when it tries to reference our object. It's not ready yet! The very last message is the console.log() from the load_terrain method, indicating that the .done function runs afterwards.

What can I do to wait until the AJAX request is complete before continuing on with my program?

njp
  • 695
  • 2
  • 8
  • 21
  • possible duplicate of [How to return the response from an AJAX call?](http://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-ajax-call) – adeneo Sep 28 '13 at 12:04
  • What prevents you from moving the functions that rely on your ajax call into the `.done( ... )` function. – Sumurai8 Sep 28 '13 at 12:07
  • I was hoping for guidance on this particular case more than anything. @Sumurai8 - I thought it might be ugly to have the main loop, outside of the TerrainObject running inside one of its methods? – njp Sep 28 '13 at 12:09
  • 1
    Let the load_terrain and draw_screen methods set a flag and let `mainloop()` do a dummy-loop until the flags that were set by load_terrain and draw_screen are true. – Sumurai8 Sep 28 '13 at 12:16
  • 1
    As of jQuery 1.8, the use of async: false with jqXHR is deprecated; you must use the success/error/complete callback options instead of the corresponding methods of the jqXHR object such as jqXHR.done() or the deprecated jqXHR.success() – ram Sep 28 '13 at 16:27

2 Answers2

5

Javascript is an event driven language. You do not have a mainloop, but you have events that trigger what is happening.

Here, the completion of your ajax call triggers the subsquent setting up of the terrain. Thus separate the function in two :

init: function() 
{
    TerrainObj.load_terrain();
},
init_terrain: function()
{
    TerrainObj.generate_display_layer(PlayerObj);
    GameObj.update();
    ScreenObj.draw_screen(TerrainObj);
    ScreenObj.update_screen(TerrainObj);
    mainloop();
},
load_terrain: function()
{
    var settings = {
        type: "GET",
        url: "data/map.txt",
        aysnc: false
    };

    $.ajax(settings).done(function(result) 
    {
        this.terrain = result.split("\n");
        for (var i = 0; i < this.terrain.length; i++)
        {
            this.terrain[i] = this.terrain[i].split("")
        }
        this.init_terrain();
    });
}
Lorenz Meyer
  • 19,166
  • 22
  • 75
  • 121
1

Check the comment section in the below block of code

    $.ajax(settings).done(function(result) 
    {
        this.terrain = result.split("\n");
        for (var i = 0; i < this.terrain.length; i++)
        {
            this.terrain[i] = this.terrain[i].split("")
        }
        /*******************************************/
        //Place a new function call here, to the function that contains the calls to your 
        //functions, or other logic, that require the array to be populated.
        /*******************************************/
    });
Justin Russo
  • 2,214
  • 1
  • 22
  • 26