2012-06-13 23 views
3

我有這樣一個遞歸查詢(注:這只是一個例子):節點mysql的時機

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

這不工作,因爲timmings都錯了,代碼不等待查詢。

我試着這樣做:

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

,但他只是凍結的同時,我失去了什麼?

+1

你已經基本錯過了Node.js和你可能用於編程的環境之間最好的文檔記錄和最重要的變化。你是怎麼管理的? – ceejayoz

回答

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並獲得最終結果。

2

每個Node.js的過程是單線程的,所以行

while(Done != true){}; 

接管線,而那可能會設置Done爲true回調永遠不會被運行,因爲THEAD被封鎖無限循環。

您需要重構您的程序,以便取決於查詢結果的代碼包含在回調本身中。例如,使MyQuery採取回調參數:

MyQuery = function(QueryString, callback){ 

然後在你database.query回調結束調用回調 - 甚至爲它供給database.query回調。

1

不幸的是,凍結是正確的行爲,因爲Node是單線程的。

您需要一個調度程序包來解決這個問題。就我個人而言,我一直在使用Fibers-promise來解決這類問題。您可能想看看這個或另一個承諾庫或異步