我正在尝试以OO风格使用Javascript,并且一种方法需要进行远程调用以获取一些数据,以便网页可以使用它。我已经创建了一个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;
}
}
网页本身称之为:
$('#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());
}
});
问题是有时addresses
是莫名其妙的空(即长度= 0)。在Firebug中,XHR选项卡显示带有预期数据的响应,如果我在success方法中设置了一个警告长度是正确的,但在我尝试返回该值时,该方法之外,有时(但并非总是如此) )空,我的文本框不会填充。有时候它会显示为空,但文本框无论如何都会正确填充。
我知道我可以通过删除单独的类并将整个ajax调用填充到事件处理程序中来完成此操作,但我正在寻找一种方法来正确执行此操作,以便在必要时可以重用该函数。有什么想法吗?
答案 0 :(得分:2)
简而言之,你不能像尝试使用异步ajax调用那样做。
Ajax方法通常是异步运行的。因此,当ajax函数调用本身返回时(代码中有return addressList
),实际的ajax网络尚未完成且结果尚未知晓。
相反,您需要重新编写代码流的工作方式,并仅在成功处理程序或从成功处理程序调用的函数中处理ajax调用的结果。只有在调用成功处理程序时,才会完成ajax网络并提供结果。
简而言之,在使用异步ajax调用时,您无法执行正常的过程编程。您必须改变代码的结构和流程。它确实使事情变得复杂,但使用异步ajax调用的用户体验好处是巨大的(浏览器在网络操作期间不会锁定)。
以下是如何重构代码,同时使用回调函数保持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());
}
});
});
答案 1 :(得分:2)
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());
}
}
或者如果你不想进行另一个函数调用,请使ajax调用同步。现在,它在数据被推入数组之前返回数组
答案 2 :(得分:0)
根本没有莫名其妙,该名单将在未来不确定的时间内填补。
规范方法是在成功处理程序中完成工作,也许是通过传递自己的回调。您也可以使用jQuery's .when
。
答案 3 :(得分:0)
AJAX调用是异步的,这意味着它们不能与程序的常规流程一起运行。执行时
if (addresses.length > 0) {
addresses
实际上是空的,因为程序没有等待AJAX调用完成。