dan
dan

Reputation: 2957

javascript code execution and ajax async

I have read allot about function expressions vs declaration, callbacks, hoisting, and I get the general idea of most of this but I guess I can't quite grasp the concept because of the below code, let me post the code and then ask the real questions.

    var url = "beverages.txt";


   var GridModel = function () {
        this.items = ko.observableArray();
        var me = this;
        $.ajax({
            datatype: 'json',
            url: "beverages.txt"
        }).done(function (data) {
            debugger;
            var jsonData = $.parseJSON(data);
            me.items(jsonData);
        });
    };


    var model = new GridModel();

    // prepare the data
    var source =
    {
        datatype: "observablearray",
        datafields: [
            { name: 'name' },
            { name: 'type' },
            { name: 'calories', type: 'int' },
            { name: 'totalfat' },
            { name: 'protein' },
        ],
        id: 'id',
        localdata: model.items
    };

    var dataAdapter = new $.jqx.dataAdapter(source);

    $("#grid").jqxGrid(
    {
        width: 670,
        source: dataAdapter,
        theme: 'classic',
        columns: [
          { text: 'Name', datafield: 'name', width: 250 },
          { text: 'Beverage Type', datafield: 'type', width: 250 },
          { text: 'Calories', datafield: 'calories', width: 180 },
          { text: 'Total Fat', datafield: 'totalfat', width: 120 },
          { text: 'Protein', datafield: 'protein', minwidth: 120 }
        ]
    });

    ko.applyBindings(model);
});

Ok so this code works fine, it calls the ajax request by var model = new GridModel();. The problem is that if I add a debugger; statement after var model = new GridModel(); it fails. Also the debugger statements inside of the ajax request don't fire, however if I remove the debugger statement after the var model = new GridModel(); then ajax fires and I can debug the request. Why does it fail with the additional debugger, is it because var GridModel is an Expression.

Basically want I would like to do is is create a declaration function that I can call and when ajax request is done I return the observableArray me. If I change the function like this

  function GridModel (param1,param2) {
            this.items = ko.observableArray();
            var me = this;
            $.ajax({
                datatype: 'json',
                url: "beverages.txt"
            }).done(function (data) {
                debugger;
                var jsonData = $.parseJSON(data);
                me.items(jsonData);
            });
            return me
        };

Then I would like to just be able to call that function like this var myitems = GridModel(param1,param2) with the expectation that myitems will now hold the results of the ajax request. I just don't fully understand how the code execution flow works, If someone could explain why the bottom function doesn't work and how to get it to work I would appreciate it.

Thanks, Dan

Upvotes: 0

Views: 1055

Answers (2)

Olaf Dietsche
Olaf Dietsche

Reputation: 74098

When $.ajax(...).done(...) returns, the program flow continues.

But the ajax call isn't finished yet, because in the background it sends data to the server and waits for a response. This is the asynchronous part. When the response finally arrives from the server, the part in .done(...) is executed

function (data) {
    debugger;
    var jsonData = $.parseJSON(data);
    me.items(jsonData);
}

This is where and when the returned data is processed.

What you describe with var myitems = GridModel(param1,param2) is a synchronous method. It calls to the server stops further processing and waits for the response.

While this is possible, it also blocks the whole program flow. That's why an ajax call is asynchronous and the response dealt with in a callback function.

What you want to do synchronously

var myitems = GridModel(param1,param2);
// do something with myitems

is done asynchronously this way

$.ajax(...).done(function(data) {
    // 1. do something with myitems
});

// 2. this will run usually *before* number 1. above

Upvotes: 2

bfavaretto
bfavaretto

Reputation: 71939

If you have an asynchronous operation (like an Ajax request), and everything else depends on its result, resume your program's flow from the callback. You can't use return statements, it only works for synchronous code.

You may want to modify your GridModel constructor to take a callback as a parameter:

var GridModel = function (callback) {
    this.items = ko.observableArray();
    $.ajax({
        datatype: 'json',
        url: "beverages.txt"
    }).done(callback);
};

Then resume your program flow from inside the callback:

function resumeMyProgramFlow(data) {
    // Now you can use the data, resume flow from here
    debugger;
    var jsonData = $.parseJSON(data);
    model.items(jsonData);
    // etc.
}

And instantiate GridModel like this:

var model = new GridModel(resumeMyProgramFlow);

Upvotes: 3

Related Questions