2017-08-05 32 views
0

此代碼是否遵守NodeJS異步處理方式?它完全正常工作,但我不明白爲什麼res.renderDatabase.findOne回調中,而不在Database.aggregate回調中,即使我使用Database.findOneDatabase.aggregate的結果。這段代碼爲什麼工作? (NodeJS/Express異步回調)

但是,如果我把res.renderDatabase.aggregateDatabase.findOne兩個之外,但仍然是router.get回調裏面,那麼代碼將不能在所有(編輯工作:當然,在這種情況下,我宣佈變量在數據庫查詢之外)。怎麼來的?什麼是正確的NodeJS做事方式?

由於

var _   = require('lodash'); 
var express = require('express'); 
var Database = require('../models/database'); 
var router = express.Router(); 
router.get('/:XXXX', function(req, res, next) { 
var XXXX = req.params.XXXX; 

var aggregationResults; 
Database.aggregate([ 
    // pipeline 
], function(err, results) { 
    aggregationResults = results; 
    if (err) return next(err); 
}); 

Database.findOne({XXXX: XXXX}, function(err, XXXXresult){ 
    if(err) return next(err); 

    res.render('page', {XXXXresult: XXXXresult, aggregationObject : aggregationResults[0]}); 


}); 

});

+0

嘗試閱讀關於範圍 https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20%26%20closures/ch5.md –

+0

@AhmadRezk是的,當然,變量在正確的範圍內聲明。 – Emilio

回答

1

如果您將res.render移到findOne回調之外,它將在回調之前執行 - 您將不會有任何數據。那些數據庫操作將完成路由器(req, res, next)回調,畢竟。

在您當前的代碼中,假設aggregatefindOne函數是異步函數,那麼您有競爭條件。如果findOne回撥在aggregate回撥前執行,您將得到TypeError,因爲aggregationResults將不確定。

解決此問題的最簡單方法是將findOne調用放入aggregate回調中。但這實際上並不是一個好主意,因爲這兩個函數會一個接一個地執行,這比同時執行它們要慢。

你應該真的在做什麼是使用Promise,並使用類似Promise.all這樣的兩個承諾在兩個操作完成後發送響應。

+0

那麼,我該如何解決「競爭條件」呢? (抱歉問:/) – Emilio

+0

@Emilio編輯。 –

+0

對不起,爲什麼把'findOne'放在'aggregate'回調中不是個好主意?謝謝 – Emilio

2

在您的代碼中,您調用兩個異步數據庫函數並將回調傳遞給每個函數。在這裏,您首先調用Database.aggregate()並傳遞一個回調,該回調將結果存儲在變量中,即aggregationResults。然後你打電話給Database.findOne()並將回調傳遞給它,它發送兩個呼叫的結果。

這是因爲你的第一個數據庫調用(Database.aggregate())在第二個數據庫調用之前解析(即Database.findOne())。所以在你的第二個數據庫的回調中,你假設第一個數據庫調用的結果是可用的。

但這可能並非總是如此。例如,有可能第一個數據庫可能會失敗,第二個數據庫會通過。在那種情況下,沒有第一個數據庫的結果。

什麼是正確的NodeJS做事方式?

早先它曾經是一個嵌套的回調,但今天你應該使用諾言。然後,您的代碼將是這個樣子:

Database.aggregate([pipeline]).then(function(results) { 
    aggregationResults = results; 
    return Database.findOne({XXXX: XXXX}); 
}).then(function(XXXXresult){ 
    res.render('page', {XXXXresult: XXXXresult, aggregationObject : aggregationResults[0]}); 
}); 

您可以使用圖書館像bluebird到promisify你的數據庫的方法。

+0

此代碼在沒有藍鳥或僅與藍鳥工作?謝謝! – Emilio

+0

如果您的數據庫方法已經返回承諾,那麼它將工作。否則,您需要修改數據庫方法,使其返回承諾。你既可以使用藍鳥類庫,也可以使用nodejs的本地承諾來提供它們。 –

+0

我建議你先閱讀一下關於承諾的內容,然後再直接跳到這裏。 –