【问题标题】:Handling callback of asynchronous calls处理异步调用的回调
【发布时间】:2014-05-06 21:08:37
【问题描述】:

所以。

我有一个关于处理对 Azure 数据库的 Windows Azure 移动服务异步调用的问题。

现在,我正在发布一个带有数组的对象,我又在我的 WAMS api 端点中循环。

循环获取数组中的当前对象,并将其与唯一 ID 一起推送到数据库。这会从最后插入的行返回行 ID,并在回调中获取它并实例化另一个异步调用。
然后我在这里插入最后插入的行 id,以及数组当前循环中对象的一堆属性。

但是,这似乎表现得很奇怪,并在我的第二个异步调用的所有列中插入了相同的信息。

for (var i = 0; i < object.array.length; i++) {

    var mssql = request.service.mssql,
        prop1 = object.array[i].prop1,
        prop2 = object.array[i].prop2,
        user  = object.user.userid;

    mssql.query("exec stored_procedure ?, ?", [user, prop1], {
        success: function (res) {

            var insertedid = res[0];

            if (typeof insertedid === 'undefined') {
                return;
            } else {
                insertedid = insertedid.ID;
            }

            mssql.query("exec stored_procedure_2 ?, ?", [insertedid, prop2], {

                //success

            });

        }
    });
}

我可能做错了什么,因为我不太喜欢我制作的东西,但考虑到我对 node.js 的熟悉,就是这样。

【问题讨论】:

    标签: node.js azure azure-mobile-services


    【解决方案1】:

    这是 async.js 的一个可能实现。如果您有两个以上的属性,则需要动态生成“insertPropX”函数,但这应该可以帮助您入门。

    var mssql = request.service.mssql;
    var user = object.user;
    
    function insertProp1(obj, cb) {
      mssql.query("exec stored_procedure ?, ?", [user.userid, obj.prop1], {
        success: function (res) {
            var inserted = res[0];
            if (!inserted) {
              return cb('prop1 not inserted for userid: ' + user.userid);
            }
            // pass the ID and the object to the next
            // function in the "waterfall" chain
            cb(null, inserted.ID, obj);
        }
      });
    }
    
    function insertProp2(id, obj, cb) {
      mssql.query("exec stored_procedure_2 ?, ?", [id, obj.prop2], {
        success: function (res) {
          var inserted = res[0];
          if (!inserted) {
            return cb('prop2 not inserted for id: ' + id);
          }
          // since this is the last function in
          // the "waterfall" chain, we don't need
          // to pass anything along
          cb(null);
        }
      });
    }
    
    // for each object in the array...
    async.each(object.array, function iterator (obj, cb) {
      // insert properties in order, passing the
      // insertion ID as an argument
      async.waterfall([
        insertProp1.bind(null, obj),
        insertProp2
      ], cb);
    }, function allDone (err) {
      if (err) {
        console.log(err);
      }
      // all done
    });
    

    【讨论】:

    • 感谢您提供如此详尽的回答,这为我提供了了解应该如何完成的模式所需的知识。我在这里对两个答案都加了箭头,但你的答案赢得了我的正确答案。那么第一个异步任务中的回调函数将信息传递给我接受的下一次迭代?
    • 很高兴我能帮上忙。正确,瀑布中的每个函数都将参数传递给下一个函数。我强烈建议深入研究 async.js 库,因为它还有许多其他很棒的功能。
    • 在定义应该将哪些参数传递给瀑布中的函数时遇到一些问题。我有比我上面展示的例子更多的论点。在每次 async.each 迭代中,我需要将大约 4 个参数传递给它们中的每一个。我在传递参数时记录参数,返回错误 var async.each(interaction.Locs, function (interaction.CID, location, uname, org, cb) { async.waterfall( [ insertCL.bind(null, interaction. ControlID, 位置, uname, org), insertLOQ ], cb ); }
    【解决方案2】:

    循环的执行速度比外部查询完成并进行回调要快。因此,在每个回调执行时,它们都使用i 的当前(和最终)值,而不是执行外部查询时的值。

    用一个简单的循环来说明这一点,显示正在发生的事情:

    for (var i = 0; i < 10; i++) {
        setTimeout(function(){
          console.log('the value for i is', i);
        },100);
    }
    

    你会看到这个小程序不会打印一个序列,而是打印 10 次:

    the value for i is 10
    

    使用promises列出几个库或选项)或async链接到 github 页面)之类的工具是解决此问题的两个潜在解决方案。

    【讨论】:

      猜你喜欢
      • 2021-04-16
      • 1970-01-01
      • 1970-01-01
      • 2016-12-13
      • 2016-08-08
      • 1970-01-01
      • 1970-01-01
      • 2018-09-01
      • 2021-06-17
      相关资源
      最近更新 更多