2011-07-13 121 views
2

我使用Mongoose和Node.js,並具有以下代碼,在所有save()調用完成後調用回調。但是,我覺得這是一種非常骯髒的做法,並且希望看到完成這件事的正確方法。如何等待所有異步調用完成

function setup(callback) { 

    // Clear the DB and load fixtures 
    Account.remove({}, addFixtureData); 

    function addFixtureData() { 
    // Load the fixtures 
    fs.readFile('./fixtures/account.json', 'utf8', function(err, data) { 
     if (err) { throw err; } 
     var jsonData = JSON.parse(data); 
     var count = 0; 
     jsonData.forEach(function(json) { 
      count++; 
      var account = new Account(json); 
      account.save(function(err) { 
      if (err) { throw err; } 
      if (--count == 0 && callback) callback(); 
      }); 
     }); 
    }); 
    } 
} 
+0

我使用['after'(HTTP://計算器。com/questions/6597493/synchronous-database-queries-with-node-js/6620091#6620091)功能。這樣簡單的實用功能可以幫助很多。 – Raynos

+0

這就是開發者有時稱之爲[意大利麪代碼](http://en.wikipedia.org/wiki/Spaghetti_code)「。 [這是雅虎視頻教程](http://www.yuiblog.com/blog/2010/12/06/video-yuiconf2010-croucher/)解釋如何防止這種情況。我喜歡使用來自Caolan McMahon的幫助防止意大利麪代碼的庫,例如[異步](https://github.com/caolan/async)。可以在[this node_modules section](https://github.com/joyent/node/wiki/modules#async-flow))找到更多。 – Alfred

回答

5

您可以通過使用圖書館像asyncStep清理代碼位。

而且,我已經寫了處理負荷燈具爲你一個小模塊,所以你只是做:

var fixtures = require('./mongoose-fixtures'); 

fixtures.load('./fixtures/account.json', function(err) { 
    //Fixtures loaded, you're ready to go 
}; 

Github上: https://github.com/powmedia/mongoose-fixtures

這也將載入的夾具文件的目錄,或對象。

+0

如果使用燈具庫,我建議使用更快,更主動維護的以下新項目:https://github.com/powmedia/pow-mongodb-fixtures – evilcelery

+0

是的.. pow-mongodb-fixtures速度更快,但是貓鼬夾具將驗證您的夾具是否符合貓鼬模型(例如,字段匹配等)。它也可以使用虛擬屬性,這對於燈具數據非常有用。 –

0

這實際上是正確的做法,或多或少。你在做什麼是一個並行循環。你可以將它抽象成它自己的「異步並行foreach」函數,如果你想(而且很多的話),但這是做並行循環的唯一方法。

根據你的意圖,可以做不同的一件事是錯誤處理。因爲你投擲,如果有一個單一的錯誤,該回調將永不得到執行(count將不會遞減)。所以它可能會更好做:

account.save(function(err) { 
    if (err) return callback(err); 
    if (!--count) callback(); 
}); 

並處理回調中的錯誤。這是更好的節點會議明智的。

我也會改變另一個東西給你節省每次迭代遞增count的麻煩:

var jsonData = JSON.parse(data) 
    , count = jsonData.length; 

jsonData.forEach(function(json) { 
    var account = new Account(json); 
    account.save(function(err) { 
    if (err) return callback(err); 
    if (!--count) callback(); 
    }); 
}); 
0

如果您已在項目的任何地方使用underscore.js,則可以使用after方法。你需要事先知道有多少異步呼叫,但除此之外,這是一個非常優雅的解決方案。

2

我最近創建了一個簡單的抽象,名爲wait.for以同步模式調用異步函數(基於Fibers)。它處於早期階段,但有效。正是在:

https://github.com/luciotato/waitfor

使用wait.for,你可以調用任何標準異步的NodeJS功能,就好像它是一個同步功能,而不會阻塞節點的事件循環。您可以在需要時按順序編碼。

使用wait.for你的代碼將是:

//in a fiber 
function setup(callback) { 

    // Clear the DB and load fixtures 
    wait.for(Account.remove,{}); 

    // Load the fixtures 
    var data = wait.for(fs.readFile,'./fixtures/account.json', 'utf8'); 

    var jsonData = JSON.parse(data); 
    jsonData.forEach(function(json) { 
    var account = new Account(json); 
    wait.forMethod(account,'save'); 
    } 
    callback(); 
}