2011-08-26 26 views
1

我正在写一个钛应用程序,但我遇到了与我的JavaScript的执行顺序有关的问题。Javascript:设置功能的顺序

我有一个按钮上的事件监听器。这是一个重载按钮,用于清除表格,使用HTTPClient获取约会的JSON数组,保存每个约会并刷新表格列表。问题是我正在执行表删除第一应该清除表,然后我得到的约会,但是当应用程序刷新数据表,就像它做得太快,新的约会尚未保存,因为我得到一个空的列表。现在,如果我注释掉db.deleteAll行,每次单击重新加载时,都会使用新(和现有)约会数据刷新列表。

我需要确保一切都按顺序完成,只有当前一个任务完成时。因此,必须在db.DeleteAll后执行appointmentments.download(),并且必须在var allAppointments = db.All()后执行列表刷新。

我认为问题在于约会.download()函数必须进行HTTP GET调用,然后保存结果,其他函数不会等待完成。

下面是代码:

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

下面是被调用的函数:

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; 
} 

任何帮助最感谢! Billy

回答

1

同步调用给你协调(代码不会执行,直到任何计算取决于完成)免费。使用异步调用时,必须注意协调。这通常意味着将相关代码作为函数传递给异步代码。通过的代码被称为“continuation”,这意味着“剩下的计算,从给定的点向前”。传递延续被称为(不出所料)“continuation passing style”。

要重写CPS中的代码,请确定需要协调代码的位置(调用appointments.download),然后将其余代码包装在一个函数中。

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

在一般情况下,返回值成为延续的参数。在这里,没有使用appointments.download的返回值,所以延续没有参数。

接下来,在调用中重写异步函数作为延续并通过延续。

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; 
} 

延续命名为_return,因为return语句可以模拟成一个延续(默认继续)。在异步版本中调用_return与在同步版本中调用return的效果相同。

+0

谢谢outis!这工作非常好,感谢CPS的描述! – iamjonesy

0

目前,您正在异步发出请求,这意味着您立即发出请求并从函数返回,您不会等待答案。你应该让你的电话同步,我不知道你的connxhr真的是什么,但他们可能提供方法使​​和send()方法同步。例如,如果您将JavaScript自己的XMLHttpRequestopen()方法的第三个参数设置为false,那么send()方法将不会返回,直到从服务器收到响应为止,则您的连接类可能具有相同的选项。

+0

使请求同步是一个坏主意。它将阻止所有的JS调用,直到请求完成。这可能会导致浏览器UI停止响应,从而导致它挂起的外观。 – outis

0

移动调用以将当前约会删除到onload处理程序中。这样你将删除旧的并立即添加新的数据。