3

私はこのような再帰クエリを持っています (注: これは単なる例です):

var user = function(data)
{
  this.minions = [];
  this.loadMinions = function()
  {
    _user = this;
    database.query('select * from users where owner='+data.id,function(err,result,fields)
    {
      for(var m in result)
      {
        _user.minions[result[m].id] = new user(result[m]); 
        _user.minions[result[m].id].loadMinions();
      }
    }  
    console.log("loaded all minions");
  }
}
 currentUser = new user(ID);
 for (var m in currentUser.minions)
 {
   console.log("minion found!");
 }

タイミングがすべて間違っているため、これは機能しません。コードはクエリを待機しません。

私はこれをやろうとしました:

var MyQuery = function(QueryString){
    var Data;
    var Done = false;
    database.query(QueryString, function(err, result, fields) { 
        Data = result;
        Done = true;
    });
    while(Done != true){};
    return Data;
}

var user = function(data)
{
  this.minions = [];
  this.loadMinions = function()
  {
    _user = this;
    result= MyQuery('select * from users where owner='+data.id);
    for(var m in result)
    {
      _user.minions[result[m].id] = new user(result[m]); 
      _user.minions[result[m].id].loadMinions();
    }
    console.log("loaded all minions");
  }
}
currentUser = new user(ID);
for (var m in currentUser.minions)
{
  console.log("minion found!");
}

しかし、彼はしばらくフリーズします。何か足りないのですか?

4

3 に答える 3

2

各 Node.js プロセスはシングルスレッドであるため、次の行

while(Done != true){};

がスレッドを引き継ぎ、スレッドがDone無限ループでブロックされているため、true に設定されていたはずのコールバックが実行されません。

クエリの結果に依存するコードがコールバック自体に含まれるように、プログラムをリファクタリングする必要があります。たとえば、makeMyQueryはコールバック引数を取ります。

MyQuery = function(QueryString, callback){

次に、コールバックの最後でコールバックを呼び出します。database.queryまたは、コールバックとしてdatabase.query提供することもできます。

于 2012-06-13T16:26:36.300 に答える
2

問題を解決するための最初のハードルは、Node.js の I/O が非同期であることを理解することです。これが問題にどのように適用されるかがわかれば、再帰部分ははるかに簡単になります (特に Async や Step などのフロー制御ライブラリを使用する場合)。

これは、あなたがやろうとしていることのいくつかを実行する例です (再帰を除く)。個人的には、おそらく不明な数/深さのレコードを再帰的にロードすることは避けたいと思います。代わりに、次の例のようにオンデマンドでロードします。

var User = function(data) {
    this.data = data
    this.minions;
};

User.prototype.getMinions = function(primaryCallback) {
    var that = this; // scope handle
    if(this.minions) { // bypass the db query if results cached
        return primaryCallback(null, this.minions);
    }

    // Callback invoked by database.query when it has the records
    var aCallback = function(error, results, fields) {
        if(error) {
            return primaryCallback(error);
        }

        // This is where you would put your recursive minion initialization
        // The problem you are going to have is callback counting, using a library
        // like async or step would make this party much much easier

        that.minions = results; // bypass the db query after this
        primaryCallback(null, results);
    }

    database.query('SELECT * FROM users WHERE owner = ' + data.id, aCallback);
};

var user = new User(someData);    
user.getMinions(function(error, minions) {
    if(error) {
        throw error;
    }

    // Inside the function invoked by primaryCallback(...)
    minions.forEach(function(minion) {
        console.log('found this minion:', minion);
    });
});

この例で注目すべき最大のことは、コールバックです。はdatabase.query(...)非同期であり、イベント ループが終了するのを待つ必要はありません。aCallbackこれは、クエリにコールバックを提供することで解決されます。これは、結果の準備ができたときに実行されます。そのコールバックが起動すると、レコードに対して実行したい処理を実行した後primaryCallback、最終結果で を起動できます。

于 2012-06-13T16:53:24.873 に答える
1

Node はシングルスレッドであるため、フリーズは残念ながら正しい動作です。

これを修正するには、スケジューラ パッケージが必要です。個人的に、私はこの種の問題にFibers-promiseを使用しています。これまたは別の promise ライブラリまたは async を見たいと思うかもしれません

于 2012-06-13T16:28:04.653 に答える