2

これは基本的な質問だと思いますが、しばらくの間グーグルを検索しており、満足のいく答えが見つかりません..

PHP で MySQL 選択クエリをプログラミングし、単純に結果を取得して各行をループし、ループ内で個々の行の列値に基づいてさらにクエリを実行することに慣れています。

ただし、クエリを渡すSQLオブジェクトと、クエリの実行後に呼び出されるコールバック関数に依存するjavascriptサーバー側コードを使用しています。

スコーピングの問題と、これを最もきれいに行う方法について混乱しています。たとえば、次のようなことはしたくありません。

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を使用しているため、おそらくを使用できます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実際はネストされたコールバックでずっと利用できます。

しかし、これには非常にトリッキーな部分があります。

...ネストされたクエリは非同期で実行されるため、コードは実際には一連の並列クエリを起動します (行ごとに 1 つずつ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
    });
});

上記は、ネストされたクエリを一度に 1 つずつ実行します。必要に応じて、制限された並列処理 (たとえば、一度に 4 つ) を導入するために上記を適応させるのはかなり簡単ですが、おそらく必要ではありません。

于 2010-11-30T05:46:46.843 に答える
0

result 2 番目のコールバックで使用可能になります。これが 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、正しい値を指していないことです。これも 2 番目のコールバックに継承されますが、それは参照であるため、間違った値になります。

修正は、別のクロージャを作成することです:

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 に答える
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 に答える