我正在尝试从两个不同的函数获取对象数组。这些函数在数据库中执行一些查询。
我认为问题与事务的异步性质有关。
我尝试了几种替代方法来尝试使所有过程同步,但没有成功。
我将详细介绍生成对象的代码片段:
预期的物体形状:
[
{
row:
{
prit_cd_item: 7,
prit_st_name: "1105 - Jazzboat"
},
tariffs:
[
{
cdPricing: 14,
dsPricing: "Operator tariff"
}
]
}
]
函数 getTariffByProductItem:
getTariffByProductItem: function(productItemId) {
// Return Array of tariffs
var def = new $.Deferred();
var tariffs = [];
db.transaction(function(tx) {
tx.executeSql('select pric.pric_cd_pricing, pric.pric_ds_pricing ' +
'from tga_pricings pric ' +
'where date(\'now\') <= pric.pric_dt_valid_to ' +
'and date(\'now\') >= pric.pric_dt_valid_from ' +
'and pric.pric_cd_product_item = ?',
[productItemId],
function(tx,dbResult) {
if(dbResult.rows.length) {
for(var i = 0; i < dbResult.rows.length; i++) {
tariffs.push(
{
cdPricing: dbResult.rows.item(i).pric_cd_pricing,
dsPricing: dbResult.rows.item(i).pric_ds_pricing
}
);
}
def.resolve(tariffs);
}
});
}
, function(e) {
alert("There has been an error: " + e.message);
def.reject();
});
return def.promise();
}
函数editBookPaxBuyPrepare:
editBookPaxBuyPrepare: function(productId) {
var def = new $.Deferred();
var bookingId = $( '#edit-book-pax-pricing-form' ).data('bookid');
var paxId = $( '#edit-book-pax-pricing-form' ).data('paxid');
var productItems = [];
// Check for actual data
db.transaction(function(tx) {
// Get product items for product
tx.executeSql('select prit.prit_cd_item, prit.prit_st_name ' +
'from tga_products_catalog prod ' +
'inner join tga_product_items prit ' +
'on prit.prit_cd_product = prod.prod_cd_product ' +
'where prod.prod_cd_product = ?',
[ productId ],
function(tx, dbResult) {
if(dbResult.rows.length) {
// Set form action to EDIT
$('#edit-book-pax-buy-form').data('formaction', 'edit');
// Set product name label
$('#edit-book-pax-buy-product').text(dbResult.rows.item(0).prod_ds_product);
for(var i=0; i<dbResult.rows.length; i++) {
// For each producItem get tariffs
var dbRow = dbResult.rows.item(i);
var data = [];
$.when(bookings.getTariffByProductItem(dbRow.prit_cd_item))
.then(function(data) {
console.log("Product Item: " + dbRow.prit_st_name + " - tariffsArray: " + JSON.stringify(data));
productItems.push({ "row": dbRow, "tariffs": data });
});
}
def.resolve(productItems);
}
});
},
function(e) {
def.reject(e);
});
return def.promise();
}
调用上述两个函数的主要代码:
var listFieldset = $( '#edit-book-pax-buy-form-product-items-list' );
listFieldset.empty();
$.when(bookings.editBookPaxBuyPrepare(productId))
.done(function(productItems) {
console.log(JSON.stringify(productItems));
$( "#edit-book-pax-buy-product-item" ).tmpl( productItems ).appendTo( listFieldset );
listFieldset.trigger('create');
listFieldset.listview('refresh');
});
我得到的日志:
bookings.js:738 []
2014-11-23 20:03:06.151bookings.js:566 Product Item: 1105 - Local guide - tariffsArray: [{"cdPricing":7,"dsPricing":"Operator tariff"}]
2014-11-23 20:03:06.155bookings.js:566 Product Item: 1105 - Local guide - tariffsArray: [{"cdPricing":14,"dsPricing":"Operator tariff"}]
2014-11-23 20:03:06.159bookings.js:566 Product Item: 1105 - Local guide - tariffsArray: [{"cdPricing":15,"dsPricing":"Operator tariff"}]
2014-11-23 20:03:06.163bookings.js:566 Product Item: 1105 - Local guide - tariffsArray: [{"cdPricing":16,"dsPricing":"Operator tariff"}]
如您所见,“console.log(JSON.stringify(productItems));”在 editBookPaxBuyPrepare 函数内循环中的 console.log 行之前执行。预期的行为是相反的:等到 editBookPaxBuyPrepare 完成,然后将 returndes 数组的内容记录在 Promise 中。
我的期望是:
- 调用 editBookPaxBuyPrepare,获取产品项(每行一个)。
- 对于每一行(产品项),在每次 for 循环迭代时调用 getTariffByProductItem 获取关税数组。
- 正确创建对象后,返回主程序。
我需要一双慧眼来帮助我解决这个问题。
欢迎任何帮助!
谢谢。
最佳答案
您的问题是代码的这一部分:
for(var i=0; i<dbResult.rows.length; i++) {
// For each producItem get tariffs
var dbRow = dbResult.rows.item(i);
var data = [];
$.when(bookings.getTariffByProductItem(dbRow.prit_cd_item))
.then(function(data) {
console.log("Product Item: " + dbRow.prit_st_name + " - tariffsArray: " + JSON.stringify(data));
productItems.push({ "row": dbRow, "tariffs": data });
});
}
def.resolve(productItems);
您直接在循环之后调用 def.resolve(productItems);
但在循环内部您有 $.when(bookings.getTariffByProductItem(dbRow.prit_cd_item))
这是异步的,不会阻塞循环,因此将在调用 def.resolve(productItems);
另一个问题是 dbRow
对于所有 .then()
回调都是相同的,因为这些回调是在循环完成后执行的。
如果您打算在整个代码中以复杂方式使用Promise(包括循环),那么我建议使用完整 Promise 库而不是 jQuery。
关于JavaScript 和 JQuery : promises executing in unexpected order,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27093858/