2

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

我习惯于在 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 查询并且没有范围问题/混乱代码的标准方法是什么?谢谢!

4

4 回答 4

0

这很有趣……我从来没有听说过“服务器端 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); });
  }
}

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

于 2010-11-30T05:38:29.690 回答
0

由于您使用的是服务器端 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...

应该做的伎俩。

于 2010-11-30T05:42:13.710 回答
0

正如其他人所指出的那样,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 个)——尽管它可能不是必需的。

于 2010-11-30T05:46:46.843 回答
0

result 在第二个回调中可用,这就是 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]);
  }
});
于 2010-11-30T05:35:02.207 回答