2014-07-21 72 views
1

我正在嘗試使用promise來調用getLoginState,然後存儲該值,以便稍後使用它。爲什麼這個嵌套promise,然後在承諾的方法之前執行?

我想知道爲什麼在下面的代碼塊中,q.fcall(getLoginState)裏面的.then在getLoginState方法之前被調用?

var mysql = require('mysql'); 
var q = require('q'); 

var login = "tyler"; 
var connection = mysql.createConnection({ 
    host : 'localhost', 
    user: 'root', 
    password: 'root', 
    port: '3306', 
    database: 'root' 
}); 

var gotLoginState; 
var state; 

connection.connect(function(err) { 
    if(err != null){ 
     console.log("connection err: "+err); 
    } 

    q.nfcall(connection.query.bind(connection),"SELECT id, password, salt, gender, banned, gm, pin, pic, characterslots, tos FROM accounts WHERE name = ?",[login]) 
     .then(function (results) { 
      console.log("select: "+results[0][0]); 
//  }).then(q.fcall(getLoginState), function() { 
      q.fcall(getLoginState) 
       .then(function() { 
        console.log("gotLoginState: " + state); 
       }).catch(function (error){ 
        console.log("error in inner thing"); 
      }).done(); 
     }).catch(function (error) { 
      console.error("promise error: "+error); 
     }) 
     .done(); 
}); 

var accId = 1; 
var getLoginState = function() { 
    q.nfcall(connection.query.bind(connection), "SELECT loggedin, lastlogin, UNIX_TIMESTAMP(birthday) as birthday FROM accounts WHERE id = ?", [accId]) 
     .then(function (results) { 
      state = results[0][0].loggedin; 
     }).catch(function (error) { 
      console.log("error in chaining: "+error); 
     }).done(); 
}; 
+0

有一點需要注意(我不能確定這是否是代碼中的問題)是,在爲其賦值之前,您可能會引用'getLoginState'。這就是爲什麼我不使用'var getLoginState = function(){'定義一個函數的形式,除非它是必需的。如果你使用'function getLoginState(){'來代替它,它會被掛起並且總是被定義,然後才能使用它。 – jfriend00

+0

@ jfriend00承諾保證在異步循環的某些未來時間內執行並且從不同步 - 因此在這種情況下它不是問題。 –

回答

3

在承諾的流量控制就像同步代碼:

  • 要返回您使用return關鍵字。
  • 要發出錯誤信號,請使用關鍵字throw

承諾的工作方式 - 是等待他們。在一個NodeJS風格的「errback」回調中調用nfcall。爲了讓你的代碼工作,你需要從getLoginState回報,然後不要使用nfcall,因爲該方法已返回一個承諾:

var getLoginState = function() { // this should be nodeify probably 
    return q.nfcall(...) // note the `return` statement here 
     .then(function (results) { 
      state = results[0][0].loggedin; // do not mutate state like this 
     }).catch(function (error) {   // instead use return values 
      console.log("error in chaining: "+error); // don't suppress errors 
                 // logging is not enough 
     }); // don't do `.done` if you want to chain to it 
}; 

然後在上面部分:

// don't use the `.connect` callback, promisify it 
q.nfcall(...) // promisify that method _once_ in your real code 
.then(function (results) { 
    console.log("select: "+results[0][0]); // why just the log? 
    return getLoginState() // note this is a regular function call 
      .then(function() { // also note the `return` 
       console.log("gotLoginState: " + state); 
      }).catch(function (error){ 
       console.log("error in inner thing"); 
    }); // no done here, since we chain to it 
}).catch(function (error) { 
    console.error("promise error: "+error); 
}).done(); // you only need one `.done` at the end, and only in old 
      // promise libraries 

我想強調的是,這可能寫得更好,沒有什麼理由在這裏嵌套而不是鏈接,並且連接應該在承諾中完成 - 上面的代碼與您的代碼的作用最接近。

+0

真棒!非常感謝:)我試圖在沒有嵌套的情況下寫得更好:q.nfcall(...) .then(function(results){ console.log(「select:」+ results [0] [0]); })。然後(返回getLoginState(),函數(狀態)console.log(「gotLoginState:」+ state); })。catch(function(error){ console.error(「promise error:」+錯誤); })。done(); – Omnipotence

相關問題