【问题标题】:Javascript: Set the order of functionsJavascript:设置函数的顺序
【发布时间】:2011-08-26 11:10:17
【问题描述】:

我正在编写一个 Titan 应用程序,但我的 javascript 的执行顺序有问题。

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

我需要确保一切都按顺序完成,并且只有在上一个任务完成时才完成。因此,appointments.download() 必须在 db.DeleteAll 之后执行,并且列表刷新必须在 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;
}

非常感谢任何帮助! 比利

【问题讨论】:

    标签: javascript


    【解决方案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 具有相同的效果。

    【讨论】:

    • 谢谢outis!这非常有效,感谢您对 CPS 的描述!
    【解决方案2】:

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

    【讨论】:

    • 使请求同步是个坏主意。它将阻止所有 JS 调用,直到请求完成。这可能会导致浏览器 UI 停止响应,看起来像是挂起。
    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-03-21
      • 2017-04-21
      • 1970-01-01
      • 1970-01-01
      • 2020-09-07
      • 2014-06-20
      • 1970-01-01
      相关资源
      最近更新 更多