Javascript:嵌套回调/MySQL 结果

发布于 2024-10-05 02:29:27 字数 617 浏览 1 评论 0原文

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

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

I am sure this is a basic question, but I have been searching google for awhile and can't find a satisfactory answer..

I am used to programming MySQL select queries in PHP and simply grabbing a result, looping through each row, and within the loop doing further queries based on the column values of each individual row.

However, I'm working with javascript server side code now that relies on a SQL object where you pass the query and then a callback function that will be invoked after the query is run.

I'm confused with some of the scoping issues and how to best cleanly do this. For example, I don't want to do something like:

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
    });
  }
});

What is the standard way to write this style of nested SQL query and not have scoping issues/messy code? Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

濫情▎り 2024-10-12 02:29:27

这非常有趣...我从未听说过“服务器端 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); });
  }
}

上面的代码不存在范围问题 - 但这是我喜欢组织此类事情的好方法。

This is very interesting... I've never heard of "server-side javascript"... but none the less this might help organize your code a bit. I use this method to organize my ajax request callbacks.

using your example it would look like this.

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); });
  }
}

There are no scoping issues with your above code - but this is a nice way I like to organize this kind of thing.

留蓝 2024-10-12 02:29:27

结果 在第二个回调中可用,这就是闭包 在 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 will be available in the second callback, that's how closures in JavaScript work, the functions has access to all variables in the outer scopes it was defined in.

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();

Now, on to the problem, i will not point to the correct value, it too will be inherited to the second callback but it`s a reference and will therefore has the wrong value.

Fix is to create another closure:

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
  }
});

Or an extra 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]);
  }
});
微暖i 2024-10-12 02:29:27

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

应该可以解决问题。

Since you are using server-side Javascript, you can likely use forEach. Assuming that 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
    });
  });
});

If result is merely array-like, then this

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

should do the trick.

暗藏城府 2024-10-12 02:29:27

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

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

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

为了解决这个问题,您可以使用如下内容:

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
    });
});

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

As others have pointed out result actually will be available all the way down in the nested callback.

But there is a very tricky part to this:

...Because the nested query runs asynchronously, your code will actually fire off a bunch of parallel queries -- one for each row in result -- all running at the same time (!). This is almost certainly not what you want; and unless result is very small indeed, all the simultaneous queries will use up all your available db connections rather quickly.

To remedy this, you might use something like this:

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
    });
});

The above will run your nested queries 1-at-a-time. It's fairly easy to adapt the above to introduce limited parallelism (eg. 4-at-a-time), if you want it -- though it's probably not necessary.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文