【问题标题】:Javascript: Nested Callbacks/MySQL ResultsJavascript:嵌套回调/MySQL 结果
【发布时间】:2011-05-17 16:25:08
【问题描述】:

我确定这是一个基本问题,但是我已经在谷歌搜索了一段时间,找不到满意的答案..

我习惯于用 PHP 编写 MySQL 选择查询,然后简单地抓取结果,循环遍历每一行,并在循环内根据每一行的列值进行进一步的查询。

但是,我现在正在使用 javascript 服务器端代码,它依赖于您传递查询的 SQL 对象,然后是在查询运行后将调用的回调函数。

我对一些范围界定问题以及如何最好地干净地做到这一点感到困惑。例如,我不想做这样的事情:

SQL.query("select * from blah", function(result) { 
  for(var i = 0; i < result.length; i++) {
    SQL.query("select * from blah2 where i =" + result[i].property, function(result2) {
      //now how do I access result from here? I know this isn't scoped correctly
    });
  }
});

编写这种嵌套 SQL 查询且没有范围问题/混乱代码的标准方法是什么?谢谢!

【问题讨论】:

  • 正如每个人都指出的那样,您的代码在语法上很好——但是您应该考虑一个严重的问题,它源于 javascript 的异步特性。详情请看我下面的回答。
  • 谢谢大家。正如许多人注意到的那样,结果的范围很好,让我感到困惑的是人们指出的问题,即我指向最终的增量计数,这导致了问题。我知道异步问题,感谢 Lee 提供的解决方法。

标签: javascript scope serverside-javascript


【解决方案1】:

这很有趣...我从未听说过“服务器端 javascript”...但是这可能有助于组织您的代码。我使用这种方法来组织我的 ajax 请求回调。

使用您的示例,它看起来像这样。

SQL.query("select * from some_table", function(result){ runNestedQuery(result); });

function runNestedQuery(result){
  for(var i = 0; i < result.length; i++) {
    SQL.query("select * from blah2 where i =" + result[i].property, function(result2){ nestedResult(result2); });
  }
}

您的上述代码没有范围界定问题 - 但这是我喜欢组织此类事情的好方法。

【讨论】:

    【解决方案2】:

    result 在第二个回调中可用,这就是 closures 在 JavaScript 中的工作方式,函数可以访问定义它的外部范围内的所有变量。

    function outer() {
        var foo = 1;
        function inner() { // inherits the scope of outer
            var bla = 2;
            console.log(foo); // works!
    
            // another function in here well inherit both the scope of inner AND outer, and so on
        }
        inner();
        console.log(bla); // doesn't work, raises "ReferenceError: bla is not defined"
    }
    outer();
    

    现在,关于问题,i 不会指向正确的值,它也将被继承到第二个回调,但它是一个引用,因此会有错误的值。

    修复是创建另一个闭包:

    SQL.query("select * from blah", function(result) { 
      for(var i = 0; i < result.length; i++) {
        (function(innerResult) { // anonymous function to provide yet another scope
            SQL.query("select * from blah2 where i =" + innerResult.property, function(result2) {
              // innerResult has the correct value
            });
        })(result[i]); // pass the current result into the function
      }
    });
    

    或者一个额外的功能:

    function resultThingy(result) {
       SQL.query("select * from blah2 where i =" + result.property, function(result2) {
           // result has the correct value
       });
    }
    
    SQL.query("select * from blah", function(result) { 
      for(var i = 0; i < result.length; i++) {
        resultThingy(result[i]);
      }
    });
    

    【讨论】:

    • result 将可用,但 i 不会指向预期的索引
    【解决方案3】:

    由于您使用的是服务器端 Javascript,因此您可以使用 forEach。假设result instanceof Array == true

    SQL.query("select * from blah", function(result) { 
      result.forEach(function(item, index) {
        SQL.query("select * from blah2 where i = " + item.property, function(result2) {
          console.log(item, index, result); //works as intended
        });
      });
    });
    

    如果result 只是类似数组,那么这个

    Array.prototype.forEach.call(result, function(item, index) { // etc...
    

    应该可以解决问题。

    【讨论】:

      【解决方案4】:

      正如其他人指出的那样,result 实际上在嵌套回调中一直可用。

      但这有一个非常棘手的部分:

      ...因为嵌套查询是异步运行的,所以您的代码实际上会触发 一堆 并行查询——result 中的每一行一个——所有同时运行( !)。这几乎肯定不是你想要的;除非result 确实非常小,否则所有同时查询都会很快用完所有可用的数据库连接。

      要解决这个问题,您可以使用以下方法:

      SQL.query("select * from blah", function(result) { 
          handleBlahRow( result, 0 );
      });
      
      function handleBlahRow( result, i ) {
          if( !result || (i >= result.length)) return;
      
          SQL.query("select * from blah2 where i =" + result[i].property, function(result2) {
              // kick off the next query
              handleBlahRow( result, i+1 );
      
              // result, i, *and* result2 are all accessible here.
              // do whatever you need to do with them
          });
      });
      

      以上内容将一次运行您的嵌套查询。如果您愿意,可以很容易地调整上述内容以引入有限的并行性(例如,一次 4 个)——尽管这可能不是必需的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-06-23
        • 2016-04-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多