简体   繁体   English

从jQuery Ajax方法返回值

[英]Returning a value from a jQuery Ajax method

I'm trying to use Javascript in an OO style, and one method needs to make a remote call to get some data so a webpage can work with it. 我正在尝试以OO样式使用Javascript,一种方法需要进行远程调用以获取一些数据,以便网页可以使用它。 I've created a Javascript class to encapsulate the data retrieval so I can re-use the logic elsewhere, like so: 我创建了一个Javascript类来封装数据检索,以便可以在其他地方重用逻辑,如下所示:

 AddressRetriever = function() { 
   AddressRetriever.prototype.find = function(zip) { 
       var addressList = [];
       $.ajax({ 
           /* setup stuff */
           success: function(response) { 
               var data = $.parseJSON(response.value);
               for (var i = 0; i < data.length; i++) { 
                   var city = data[i].City; // "City" column of DataTable
                   var state = data[i].State; // "State" column of DataTable
                   var address = new PostalAddress(postalCode, city, state); // This is a custom JavaScript class with simple getters, a DTO basically.
                   addressList.push(address);
               }
           }
       });
       return addressList;
   }
 }

The webpage itself calls this like follows: 该网页本身的调用方式如下:

$('#txtZip').blur(function() { 
    var retriever = new AddressRetriever();
    var addresses = retriever.find($(this).val());

    if (addresses.length > 0) { 
        $('#txtCity').val(addresses[0].getCity());
        $('#txtState').val(addresses[0].getState());
    }
});

The problem is that sometimes addresses is inexplicably empty (ie length = 0). 问题在于,有时addresses会莫名其妙地为空(即,长度= 0)。 In Firebug the XHR tab shows a response coming back with the expected data, and if I set an alert inside of the success method the length is correct, but outside of that method when I try to return the value, it's sometimes (but not always) empty and my textbox doesn't get populated. 在Firebug中,“ XHR”选项卡显示了一个返回了预期数据的响应,如果我在成功方法内设置了警报,则长度是正确的,但是当我尝试返回值时,在该方法外,有时(但并非总是如此) )为空,则不会填充我的文本框。 Sometimes it shows up as empty but the textbox gets populated properly anyways. 有时它显示为空,但无论如何该文本框都会正确填充。

I know I could do this by getting rid of the separate class and stuffing the whole ajax call into the event handler, but I'm looking for a way to do this correctly so the function can be reused if necessary. 我知道我可以通过摆脱单独的类并将整个ajax调用填充到事件处理程序中来做到这一点,但是我正在寻找一种正确执行此操作的方法,以便可以在必要时重用该函数。 Any thoughts? 有什么想法吗?

In a nutshell, you can't do it the way you're trying to do it with asynchronous ajax calls. 简而言之,您无法像尝试通过异步ajax调用那样进行操作。

Ajax methods usually run asynchronous. Ajax方法通常运行异步。 Therefore, when the ajax function call itself returns (where you have return addressList in your code), the actual ajax networking has not yet completed and the results are not yet known. 因此,当ajax函数调用本身返回时(在代码中您具有return addressList ),实际的ajax网络尚未完成,并且结果未知。

Instead, you need to rework how the flow of your code works and deal with the results of the ajax call ONLY in the success handler or in functions you call from the success handler. 相反,您仅需要在成功处理程序或从成功处理程序调用的函数中重新设计代码流的工作方式,并处理ajax调用的结果。 Only when the success handler is called has the ajax networking completed and provided a result. 只有调用成功处理程序时,ajax网络才能完成并提供结果。

In a nutshell, you can't do normal procedural programming when using asynchronous ajax calls. 简而言之,使用异步ajax调用时无法进行常规的过程编程。 You have to change the way your code is structured and flows. 您必须更改代码的结构和流程方式。 It does complicate things, but the user experience benefits to using asynchronous ajax calls are huge (the browser doesn't lock up during a networking operation). 它确实使事情变得复杂,但是使用异步ajax调用给用户带来的好处是巨大的(在网络操作期间浏览器不会锁定)。

Here's how you could restructure your code while still keeping the AddressRetriever.find() method fairly generic using a callback function: 这是在重新AddressRetriever.find()代码的同时仍使用回调函数保持AddressRetriever.find()方法相当通用的方法:

AddressRetriever = function() { 
   AddressRetriever.prototype.find = function(zip, callback) { 
       $.ajax({ 
           /* setup stuff */
           success: function(response) { 
               var addressList = [];
               var data = $.parseJSON(response.value);
               for (var i = 0; i < data.length; i++) { 
                   var city = data[i].City; // "City" column of DataTable
                   var state = data[i].State; // "State" column of DataTable
                   var address = new PostalAddress(postalCode, city, state); // This is a custom JavaScript class with simple getters, a DTO basically.
                   addressList.push(address);
               }
               callback(addressList);
           }
       });
   }
 }

$('#txtZip').blur(function() { 
    var retriever = new AddressRetriever();
    retriever.find($(this).val(), function(addresses) {
        if (addresses.length > 0) { 
            $('#txtCity').val(addresses[0].getCity());
            $('#txtState').val(addresses[0].getState());
        }
    });

});
    AddressRetriever = function() { 
   AddressRetriever.prototype.find = function(zip) { 
       var addressList = [];
       $.ajax({ 
           /* setup stuff */
           success: function(response) { 
               var data = $.parseJSON(response.value);
               for (var i = 0; i < data.length; i++) { 
                   var city = data[i].City; // "City" column of DataTable
                   var state = data[i].State; // "State" column of DataTable
                   var address = new PostalAddress(postalCode, city, state); // This is a custom JavaScript class with simple getters, a DTO basically.
                   addressList.push(address);
                   processAddresss(addressList);
               }
           }
       });
   }
 }

function processAddresss(addressList){
     if (addresses.length > 0) { 
        $('#txtCity').val(addresses[0].getCity());
        $('#txtState').val(addresses[0].getState());
    }
}

or if you want don't want to make another function call, make the ajax call synchronous. 或者如果您不想进行其他函数调用,请使ajax调用同步。 Right now, it is returning the array before the data is pushed into the array 现在,它正在将数据推入数组之前返回数组

Not inexplicable at all, the list won't be filled until an indeterminate amount of time in the future. 根本无法解释,直到将来不确定的时间,列表才会被填充。

The canonical approach is to do the work in your success handler, perhaps by passing in your own callback. 规范的方法是在成功处理程序中完成工作,也许是通过传入自己的回调函数。 You may also use jQuery's .when . 您也可以使用jQuery的.when

AJAX calls are asynchroneous, which means they don't run with the regular flow of the program. AJAX调用是异步的,这意味着它们不会与程序的常规流程一起运行。 When you execute 执行时

if (addresses.length > 0) { 

addresses is in fact, empty, as the program did not wait for the AJAX call to complete. addresses实际上是空的,因为程序没有等待AJAX​​调用完成。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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