簡體   English   中英

在Node.js中處理異步循環的最佳模式

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM