2017-09-04 63 views
0

我是javascript新手。如何爲多個查詢使用異步並行

我試過使用async.parellel函數。 然後獲得「reviewArr」並將其返回。

請看看我的代碼。

app.get('/api/wherecritique/reviews/search/:author', function(req,res){ 
    var reviewArr = []; 
    Critique.find({author:req.params.autho}, function(err,cris){ 
     var i =0; 
     var f = function(reviewID) 
     { 
      Review.findOne({id:reviewID}, function(err, review) 
      { 
       reviewArr.push(review); 
      } 
     } 
     var tasks = {}; 
     for(var j =0; j<cris.length; j++) 
     { 
      tasks['func'+j] = f(cris[j].reviewID); 
     } 
     async.parallel(tasks, function(err, results){ 
      console.log(results); 
      res.json(reviewArr); 
     }); 
    }); 
}); 

我用了mongoose + express + node.js。 評論,評論是模型(貓鼬模式)。

當我運行這段代碼時,我收到了這條消息。 「任務不是功能」

請幫我該如何解決這個錯誤? 此致敬禮。

回答

4

您沒有正確設置功能。期望的參數是function()包含callback參數的包裝,它在包含的異步函數完成時傳遞給它。

你也真的只是想async.map而不是你在做什麼,因爲它的輸出是來自循環調用結果的數組。所以沒必要推動成果轉化爲外部變量:

app.get('/api/wherecritique/reviews/search/:author', function(req,res) { 

    Critique.find({author: req.params.author}, function(err,cris) { 

    async.map(
     cris.map(c => c.reviewID), 
     function(id, callback) { 
     Review.findOne({ id: id }, callback); 
     }, 
     function(err,results) { 
     if (err) throw err; // or something with err 
     console.log(results); 
     res.json(results); 
     } 
    ); 

    }); 
}); 

但是捫心自問,你真正應該使用的承諾而不是在這裏導入外部庫

app.get('/api/wherecritique/reviews/search/:author', function(req,res) { 

    Critique.find({author: req.params.author}, function(err,cris) { 

    Promise.all(
     cris.map(c => Review.findOne({ id: c.reviewID })) 
    ).then(results => { 
     console.log(results); 
     res.json(results); 
    }).catch(e => console.error(e)); 

    }); 

}); 

或與async/await一個更現代的方式:

app.get('/api/wherecritique/reviews/search/:author', async (req,res) => { 

    try {  
    let cris = await Critique.find({author: req.params.author}); 

    let results = Promise.all(
     cris.map(c => Review.findOne({ id: c.reviewID })) 
    ); 
    console.log(results); 
    res.json(results); 
    } catch(e) { 
    console.error(e); 
    } 

}); 

但實際上,這與JavaScript完全無關,而且您確實應該使用MongoDB功能。

要麼與$lookup如果支持:

app.get('/api/wherecritique/reviews/search/:author', async (req,res) => { 

    try {  
    let results = await Critique.aggregate([ 
     { $match: { author: req.params.author } }, 
     { $lookup: { 
     from: Review.collection.name, 
     localField: 'reviewID', 
     foreignField: 'id' 
     as: 'reviews' 
     }}, 
     { $unwind: '$reviews' } 
    ]); 

    results = results.map(r => r.reviews); 
    console.log(results); 
    res.json(results); 

    } catch(e) { 
    console.error(e); 
    } 

}); 

或者,如果你沒有這一點,那麼簡單地通過了所有id$in

app.get('/api/wherecritique/reviews/search/:author', async (req,res) => { 

    try {  
    let cris = await Critique.find({ author: req.params.author }); 

    let results = await Review.find({ id: { $in: cris.map(c => c.reviewID) } }); 
    console.log(results); 
    res.json(results); 

    } catch(e) { 
    console.error(e); 
    } 

}); 

這意味着無論是 「一」 或「兩個「對數據庫的實際調用取決於您的MongoDB版本。根本不需要循環異步調用。


最後,它真的沒有必要通過所有上述解釋,但async.parallel正確的用法是:

app.get('/api/wherecritique/reviews/search/:author', (req,res) => { 

    Critique.find({author: req.params.author}, (err,cris) => { 

    var tasks = cris.map(c => (callback) => 
     Review.findOne({ id: c.reviewID }, callback); 
    ); 

    async.parallel(
     tasks, 
     (err,results) => { 
     if (err) throw err; // or something 
     console.log(results); 
     res.json(results); 
     } 
    ) 
    }); 
}); 
+0

最好的答案是我所見過。 也是關於異步的好的講座。 非常感謝。 – fastworker399

+0

@ fastworker399您可能會考慮[接受答案](https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work),因爲這通常會向人們表明它確實是解決方案解決問題。 –

相關問題