简体   繁体   中英

Javascript: Set the order of functions

I'm writing a titanium app but I'm having an issue with the execution order of my javascript.

I have an event listener on a button. It's a reload button that clears a table, uses HTTPClient to GET a JSON array of 'appointments', saves each appointment, and refreshes a table list. The problem is I am executing the table delete first which should clear the table, then I get the appointments but when the app refreshes the datatable it's like it's doing it too soon and the new appointments haven't been saved yet because I'm getting an empty list. Now if I comment out the db.deleteAll line, each time I click reload the list is refreshed with the new (and existing) appointment data.

I need to make sure everything is done in order and only when the previous task is dfinished. So appointments.download() has to be executed AFTER db.DeleteAll and the list refresh has to be executed AFTER var allAppointments = db.All();

I think the problem is that the appointments.download() function has to make a HTTP GET call and then save the results and the other functions are not waiting until it's finished.

Here is the code:

btnReload.addEventListener('click', function(e){
    var affected = db.deleteAll();
    appointments.download();
    var allAppointments = db.all();
    Ti.API.info(allAppointments);
    appointmentList.setData(allAppointments);
});

Here are the functions that are being called:

db.deleteAll():

api.deleteAll = function(){
    conn.execute('DELETE FROM appointments');
    return conn.rowsAffected;
}

appointments.download():

var appointments = (function() {
    var api = {};
    api.download = function(){

        var xhr = Titanium.Network.createHTTPClient();
        xhr.onload = function()
        {
          var data = JSON.parse(this.responseText);
          var dl = (data.length);
          for(i=0; i<dl;i++)
          {
            //p = addRow(data,i); // returns the **arr array 
            //Ti.API.info('Saving : '+data[i].first_name);
            var contact_name = data[i].first_name + ' ' + data[i].last_name;
            var start_date = data[i].start_date;
            var reference = data[i].reference;
            var comment = data[i].comment;
            var appointment_id = data[i].quote_id;

            var lastid = db.create(appointment_id, start_date, reference, contact_name, comment);
            //Ti.API.info(lastid);
          }

        };
        xhr.open('GET','http://********.co.uk/appointments/download/');
        xhr.send();

        return;
}

Any help most appreciated! Billy

Synchronous calls give you coordination (code won't execute until any computation it depends on finishes) for free. With asynchronous calls, you have to take care of coordination. This generally means passing the dependent code as a function to the asynchronous code. The passed code is known as a " continuation ", which means "the rest of the calculation, from a given point forward". Passing continuations around is known as (unsurprisingly) " continuation passing style ".

To rewrite code in CPS, identify the point(s) where you need to coordinate the code (the call to appointments.download ), then wrap the rest of the code in a function.

btnReload.addEventListener('click', function(e){
    var affected = db.deleteAll();
    appointments.download();
    function () {
        var allAppointments = db.all();
        Ti.API.info(allAppointments);
        appointmentList.setData(allAppointments);
    }
});

In the general case, the return value becomes the argument to the continuation. Here, no return value for appointments.download is used, so the continuation takes no arguments.

Next, rewrite the asynchronous function to take the continuation and pass the continuation in the call.

btnReload.addEventListener('click', function(e){
    var affected = db.deleteAll();
    appointments.download(
        function () {
            var allAppointments = db.all();
            Ti.API.info(allAppointments);
            appointmentList.setData(allAppointments);
        });
});

...
api.download = function(_return){
    var xhr = Titanium.Network.createHTTPClient();
    xhr.onload = function() {
        var data = JSON.parse(this.responseText);
        var dl = (data.length);
        for (i=0; i<dl;i++) {
            //p = addRow(data,i); // returns the **arr array 
            //Ti.API.info('Saving : '+data[i].first_name);
            var contact_name = data[i].first_name + ' ' + data[i].last_name;
            var start_date = data[i].start_date;
            var reference = data[i].reference;
            var comment = data[i].comment;
            var appointment_id = data[i].quote_id;

            var lastid = db.create(appointment_id, start_date, reference, contact_name, comment);
            //Ti.API.info(lastid);
        }
        _return();
    };
    xhr.open('GET','http://********.co.uk/appointments/download/');
    xhr.send();

    return;
}

The continuation is named _return because the return statement can be modeled as a continuation (the default continuation). Calling _return in the asynchronous version would have the same affect as calling return in the synchronous version.

Currently you are making requests asynchronously which means you make a request and return from the function immediately, you don't wait for an answer. You should make your calls synchronous, I don't know what your conn and xhr really are but they might provide ways to make the execute() and send() methods synchronous. For example if you set the third argument of JavaScript's own XMLHttpRequest 's open() method to false then send() method will not return until a response is received from the server, your connection classes might have the same option.

Move the call to delete the current appointments into the onload handler. That way you will delete the old and immediately add the new data.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM