2016-08-30 48 views
2

我可能在這裏錯過了某處,所以我正在尋找建議。在單獨的函數中使用節點中回調的結果

我有一個nodejs服務器正在偵聽客戶端連接,並根據收到的數據調用API。

對該API的第一次調用獲取需要在後續調用中使用的ID,以將它們組合在一起。

我在哪裏掙扎的是,對API的調用必然是異步的,在回調函數中,我將ID分配給一個變量。當異步調用正在被API服務器處理時,更多數據從客戶端進入並且需要更多API調用,但是直到我知道第一次調用的結果爲止,因爲第二次調用依賴於調用的結果之前我無法觸發它們。

處理這個問題的正確方法是什麼?我覺得我應該使用Q將第一個API調用的結果承諾給第二個API,但我不確定它應該如何構造。或者我應該在第一次完成之前將API調用排隊?我會怎麼做?

例問題代碼:

var server = net.createServer(); 

//set up the callback handler 

server.on('connection', handleConnection); 

handleConnection(conn) { 
    //do some stuff... 
    firstAPICall(); 
    conn.on('data', handleData); 
} 

handleData(data) { 
    //do some stuff... 
    otherAPIcall(); 
} 

firstAPICall() { 
    client.get("http://myAPI/getID", function (data, response) { 
    conn.myID = data[0].myID; 
    } 
    } 
} 

otherAPICall() { 
    //How do I make sure I actually have a value 
    //in conn.myID from the first function??? 
    client.post("http://myAPI/storeData", { data: {myID:conn.myID, data:someData} }, function (data, response) { 
    //do some stuff... 
    } 
    } 
} 
+0

您錯過的一點是:「對該API的第一次調用獲取需要在隨後的調用中使用的ID,以將它們組合在一起」。要麼是要求,要麼不是。下定決心 – Tibrogargan

回答

1

是的,你應該使用承諾這一點。確認所有異步從第一個呼叫解決ID的承諾,然後在後續調用使用它:

handleConnection(conn) { 
    //do some stuff... 
    var idPromise = firstAPICall(); 
    conn.on('data', function handleData(data) { 
    //do some stuff... 
    otherAPIcall(idPromise).then(function(result) { 
     … 
    }); 
    }); 
} 

firstAPICall() { 
    return Q.Promise(function(resolve, reject) { 
    client.get("http://myAPI/getID", function (data, response) { 
     resolve(data[0].myID); 
    }); 
    }); 
} 

otherAPICall(idPromise) { 
    return idPromise.then(function(myID) { 
    return new Promise(function(resolve, reject) { 
     client.post("http://myAPI/storeData", { 
     data: {myID:myID, data:someData} 
     }, function (data, response) { 
     //do some stuff... 
     resolve(…); 
     }); 
    }); 
    }); 
} 

也許你應該分解出一個額外的功能,創建一個client.get調用的結果承諾。還要確保在那裏正確處理錯誤,並與他們聯繫reject。如果client將使用節點回調約定,則Q甚至有some nice helper functions

+0

我最終答應了,它似乎工作得很好 - 謝謝! – Kristan

1

嘗試使用承諾。然後用'然後'來呼叫另一個APICall()

1

我認爲你可以假設他們將在連接後立即發送數據。所以如果你有一個ID,那麼你可以簡化並只檢查其他APICall,如果沒有,你可以使用回調。承諾或async/await關鍵字可能會使事情更好,但不是必需的。

var server = net.createServer(); 

//set up the callback handler 

server.on('connection', handleConnection); 

handleConnection(conn) { 
    conn.on('data', handleData(connm, data)); 
} 

handleData(conn, data) { 
    //do some stuff... 
    otherAPIcall(conn); 
} 

checkID(conn, cb) { 
    if (!conn.myID) { 
    client.get("http://myAPI/getID", function (data, response) { 
     conn.myID = data[0].myID; 
     cb(); 
    }); 
    } else { 
    cb(); 
    } 
} 

otherAPICall(conn) { 
    checkID(conn, function() { 
    client.post("http://myAPI/storeData", { data: {myID:conn.myID, data:someData} }, function (data, response) { 
     //do some stuff... 
    }); 
    }); 
} 
0

承諾可以鏈值和與返回的值發生回調之後總是解決,

function async(value) { 
var deferred = $q.defer(); 
var asyncCalculation = value/2; 
deferred.resolve(asyncCalculation); 
return deferred.promise; 
} 

var promise = async(8) 
.then(function(x) { 
    return x+1; 
}) 
.then(function(x) { 
    return x*2; 
}) 
.then(function(x) { 
    return x-1; 
}); 
promise.then(function(x) { 
console.log(x); 
}); 

此值通過所有成功回調和因此該值9被記錄((8/2 + 1 )* 2 - 1)。

+1

是的,這就是承諾如何工作,但這與問題有什麼關係? – Bergi

+0

順便說一句,OP是使用Q,而不是角度的承諾。 – Bergi

+0

該案例展示了諾言如何清晰工作以及如何使用它。如果我很好地理解承諾,無論是Q還是Angularjs $ q,它們都基於相同的原則。如果你明白承諾是如何工作的,那麼你怎麼不能在另一個領域使用它。 – Eric