[英]The best pattern for handling async looping in Node.js
我是Node的新手,並試圖確保我使用理智的設計來構建JSON驅動的Web應用程序。
我有一堆數據存儲在Redis中,我正在通過節點檢索它,將結果流出來,因為它們來自Redis。 這是我正在做的一個很好的例子:
app.get("/facility", function(req, res) {
rc.keys("FACILITY*", function(err, replies) {
res.write("[");
replies.forEach(function (reply, i) {
rc.get(reply, function(err, reply) {
res.write(reply);
if (i == replies.length-1) {
res.write("]");
res.end();
}
else
res.write(",");
});
});
});
});
基本上我從Redis獲取一組密鑰,然后請求每個密鑰,將結果流式傳輸到半手動創建的JSON(Redis中的字符串已經是JSON)。 現在這很好用,但我不禁想到i == replies.length-1有點亂?
我可以用Redis中的mget完成所有這些,但這並不是我想要得到它的重點; 這是如何最好地處理與forEach的異步循環,流式輸出和優雅地關閉與res.end的連接與循環完成。
這是最好的方式,還是我可以遵循更優雅的模式?
上面的代碼可能無法達到預期效果。 你按順序啟動每個.get()
,但它們可能不會按順序回調 - 所以結果可以按任何順序流出。 如果要流式傳輸結果而不是在內存中收集它們,則需要按順序使用.get()
。
我認為caolan的異步庫使這很容易。 這是您可以使用它來按順序獲取每個項目的一種方法(警告,未經測試):
app.get("/facility", function(req, res) {
rc.keys("FACILITY*", function(err, replies) {
var i = 0;
res.write("[");
async.forEachSeries(replies, function(reply, callback){
rc.get(reply, function(err, reply) {
if (err){
callback(err);
return;
}
res.write(reply);
if (i < replies.length) {
res.write(",");
}
i++;
callback();
});
}, function(err){
if (err) {
// Handle an error
} else {
res.end(']');
}
});
});
});
如果您不關心訂單,請改用async.forEach()
。
如果您不介意收集結果並希望它們按順序返回,您可以像這樣使用async.map()
(警告,也未經測試):
app.get("/facility", function(req, res) {
rc.keys("FACILITY*", function(err, replies) {
async.map(replies, rc.get.bind(rc), function(err, replies){
if (err) {
// Handle an error
} else {
res.end('[' + replies.join(',') + ']');
}
});
});
});
您可以使用異步庫,它提供了一些方便的循環方法,例如forEach:
forEach(arr,iterator,callback)
將迭代器函數並行應用於數組中的每個項目。 使用列表中的項目調用迭代器,並在完成時調用它。 如果迭代器將錯誤傳遞給此回調,則會立即調用forEach函數的主回調並顯示錯誤。
注意,由於此函數並行地將迭代器應用於每個項目,因此無法保證迭代器函數將按順序完成。
例
// assuming openFiles is an array of file names and saveFile is a function
// to save the modified contents of that file:
async.forEach(openFiles, saveFile, function(err){
// if any of the saves produced an error, err would equal that error
});
但我不禁想到i == replies.length-1有點凌亂?
我聽說很多人都這么說。 我就是這樣做的:
app.get("/facility", function(req, res, next) {
rc.keys("FACILITY*", function(err, replies) {
if (err) return next(err);
var pending = replies.length;
res.write("[");
replies.forEach(function (reply) {
rc.get(reply, function(err, reply) {
res.write(reply);
if (!--pending) {
res.write("]");
return res.end();
}
res.write(",");
});
});
});
});
顯然,手工制作它並不太漂亮,這就是人們將它抽象成圖書館或其他功能的原因。 但無論喜歡與否,這就是你如何進行異步並行循環。 :)
您可以使用之前提到的異步庫來隱藏討厭的內臟。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.