JavaScript 和 JQuery : promises executing in unexpected order

标签 javascript jquery mysql promise javascript-objects

我正在尝试从两个不同的函数获取对象数组。这些函数在数据库中执行一些查询。

我认为问题与事务的异步性质有关。

我尝试了几种替代方法来尝试使所有过程同步,但没有成功。

我将详细介绍生成对象的代码片段:

预期的物体形状:

[
    {
        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/

相关文章:

javascript - 检查复选框属性时出错

javascript - 在 Javascript 中测量文本节点的边界框

javascript - jQuery 无法读取未定义的属性 'setAttribute'

mySQL多表选择超过3个表

PHP session 、超时和跟踪

javascript - React 找不到模块

javascript - chop 长字符串的聪明方法

MySQL 对计算列进行排序

javascript - Azure 应用服务在 URL 中添加 '/'

javascript - 第一次打开时加载所有图片的简单图库