54

我能找到的所有用于渲染带有猫鼬结果的页面的东西都说要这样做:

users.find({}, function(err, docs){
    res.render('profile/profile', {
        users:     docs
    });
});

我怎样才能从查询中返回结果,更像这样?

var a_users = users.find({}); //non-working example

这样我就可以获得多个结果以在页面上发布?

喜欢:

/* non working example */
var a_users    = users.find({});
var a_articles = articles.find({});

res.render('profile/profile', {
      users:    a_users
    , articles: a_articles
});

这可以做到吗?

4

6 回答 6

67

您正在尝试强制使用同步范式。就是行不通。node.js 在大多数情况下是单线程的——当 io 完成时,会产生执行上下文。信令通过回调进行管理。这意味着您要么拥有嵌套回调、命名函数或流控制库,以使事情看起来更漂亮。

https://github.com/caolan/async#parallel

async.parallel([
   function(cb){
      users.find({}, cb);
   },
   function(cb){
      articles.find({}, cb);
   }
], function(results){
   // results contains both users and articles
});
于 2011-05-31T00:59:50.827 回答
19

I'll play the necromancer here, as I still see another, better way to do it.

Using wonderful promise library Bluebird and its promisifyAll() method:

var Promise = require('bluebird');
var mongoose = require('mongoose');

Promise.promisifyAll(mongoose); // key part - promisification

var users, articles; // load mongoose models "users" and "articles" here

Promise.props({
    users: users.find().execAsync(),
    articles: articles.find().execAsync()
  })
  .then(function(results) {
    res.render('profile/profile', results);
  })
  .catch(function(err) {
    res.send(500); // oops - we're even handling errors!
  });

Key parts are as follows:

Promise.promisifyAll(mongoose);

Makes all mongoose (and its models) methods available as functions returning promises, with Async suffix (.exec() becomes .execAsync(), and so on). .promisifyAll() method is nearly-universal in Node.JS world - you can use it on anything providing asynchronous functions taking in callback as their last argument.

Promise.props({
    users: users.find().execAsync(),
    articles: articles.find().execAsync()
  })

.props() bluebird method takes in object with promises as its properties, and returns collective promise that gets resolved when both database queries (here - promises) return their results. Resolved value is our results object in the final function:

  • results.users - users found in the database by mongoose
  • results.articles - articles found in the database by mongoose (d'uh)

As you can see, we are not even getting near to the indentation callback hell. Both database queries are executed in parallel - no need for one of them to wait for the other. Code is short and readable - practically corresponding in length and complexity (or rather lack of it) to wishful "non-working example" posted in the question itself.

Promises are cool. Use them.

于 2015-04-26T17:39:31.087 回答
16

简单的方法:

var userModel = mongoose.model('users');
var articleModel = mongoose.model('articles');
userModel.find({}, function (err, db_users) {
  if(err) {/*error!!!*/}
  articleModel.find({}, function (err, db_articles) {
    if(err) {/*error!!!*/}
    res.render('profile/profile', {
       users: db_users,
       articles: db_articles
    });
  });
});

实际上,Node.js 中的每个函数都是异步的。猫鼬的发现也是如此。如果你想连续调用它,你应该使用像幻灯片库这样的东西。

但是在您的情况下,我认为最简单的方法是嵌套回调(这允许为选定的先前用户查询文章)或在异步库的帮助下完全并行(请参阅Flow control / Async goodies)。

于 2011-05-31T00:49:51.020 回答
1

我有一个函数,我经常使用它作为对 Node 函数的返回。

function freturn (value, callback){
    if(callback){
        return callback(value); 
    }
    return value; 
}; 

然后我在所有签名中都有一个可选的回调参数。

于 2013-01-27T23:52:42.320 回答
1

我正在处理一个非常相似的事情,但使用来自客户端的 socket.io 和 DB 访问。我的发现是在数据库有机会获取数据之前将我的数据库的内容扔回客户端......所以我将在这里分享我的发现:

我检索数据库的功能:

//读板 - 完整的数据库

var readBoards = function() {
        var callback = function() {
            return function(error, data) {
                if(error) {
                    console.log("Error: " + error);
                }
                console.log("Boards from Server (fct): " + data);

            }
        };

        return boards.find({}, callback());
    };

我的套接字事件监听器:

socket.on('getBoards', function() {
        var query = dbConnection.readBoards();
        var promise = query.exec();
        promise.addBack(function (err, boards) {
            if(err)
                console.log("Error: " + err);
            socket.emit('onGetBoards', boards);
        });
    });

所以为了解决这个问题,我们使用猫鼬给我们的承诺,然后一旦我们从数据库接收到数据,我的套接字就会将它发送回客户端......

物有所值...

于 2013-04-23T10:32:59.253 回答
1

您可以通过以下代码获得所需的结果。希望这会帮助你。

var async = require('async');

// custom imports
var User = require('../models/user');
var Article = require('../models/article');

var List1Objects = User.find({});
var List2Objects = Article.find({});
var resourcesStack = {
    usersList: List1Objects.exec.bind(List1Objects),
    articlesList: List2Objects.exec.bind(List2Objects),
};

async.parallel(resourcesStack, function (error, resultSet){
    if (error) {
        res.status(500).send(error);
        return;
    }
    res.render('home', resultSet);
});
于 2018-06-24T13:10:48.323 回答