Nodejs延迟返回“require”

时间:2014-04-18 05:41:50

标签: javascript node.js asynchronous require

我的设置如下:

  • Nodejs Server
  • server.js需要utils.js
  • utils.js将数据从mongodb加载到内存中并将其导出
  • server.js使用utils.js导出
  • 的变量

我担心的问题是mongodb调用是异步的。 utils.js在mongodb调用完成之前返回,这意味着server.js在require之后继续执行时将使用未定义的变量。

解决此问题的最佳方法是什么?我唯一能想到的是将我的server.js代码包装在一个巨大的回调中,并将其传递给进行mongodb调用的函数。对我来说这似乎有点乱,有没有更好的方法呢?

代码:

server.js
var utils = require("./modules/utils.js");
console.log(utils);
//Do whatever

utils.js
var mods = [];
var db = require("mongojs").connect("localhost", ["modules"]);
db.modules.find({}, function(err, modules){
    mods = modules;
});
module.exports = mods;

2 个答案:

答案 0 :(得分:5)

你所指的是“回调地狱”。最简单的方法是使用简化它的Promise库。

我使用了名为bluebird的节点包。

var mysql = require("mysql");
var hash = require("password-hash");
var Promise = require("bluebird");
var settings = require("../settings");

Promise.promisifyAll(require("mysql/lib/Connection").prototype);
Promise.promisifyAll(require("mysql/lib/Pool").prototype);

var db_config = {
    user:settings.db.user,
    password:settings.db.password,
    database:settings.db.database
};

var con = mysql.createPool(db_config);

function query(sql) {
    return con.getConnectionAsync().then(function(connection) {
        return connection.queryAsync(sql)
        .spread(function(rows,fields) {
            return rows;
        }).finally(function() {
            connection.release();
        });
    });
}

这是我编写的一个非常基本的数据库模块,它使用bluebirdpromisify数据库对象。

以下是它的使用方法。它回报了一个承诺!这样做的好处是它不仅可以恢复回调地狱的混乱,它还可以确保您的代码异步运行,并且在事情停止处理之前函数不会返回,就像在这种情况下,数据库查询一样。

function login(user) {
    //check for player existance
    var query = 'SELECT p.name,p.password,p.id, pd.x, pd.y FROM player p INNER JOIN player_data pd ON p.id = pd.id WHERE p.name='+mysql.escape(user);
    return db.select(query).then(function(rows) {
        if (!rows.length) return;
        return [
            rows[0]
        ];
    });
}

注意你如何返回一个promise,这样你就可以调用thenspread方法来获取刚查询过的那些数据库值,而不必担心rows是否会被定义当你想要使用它时。

答案 1 :(得分:0)

正如您所说,您需要将整个服务器包装在回调中。 Node.js以这种方式工作,它本质上是异步的。服务器需要经过3个阶段:init,serve和deinit。在您的情况下,该数据库代码进入init阶段。你可以写这样的东西。

//server.js
var utils = require ("./modules/utils");

var init = function (cb){
  //init the utils module, the http server and whatever you need
  utils.init (function (error){
    if (error) return handleError (error);
    cb ();
  });
};

var serve = function (){
  //Start listening to the http requests
};

var deinit = function (cb){
  //This is typically executed when a SIGINT is received, see link1
};

init (serve);

//utils.js
//You could write a wrapper for the db instance, see link2
var mongodb = require ("mongojs");
var db;

module.exports.init = function (cb){
  db = mongodb.connect ("localhost", ["modules"]);
  db.modules.find ({}, function (err, modules){
    if (err) return cb (err);
    cb (null, modules);
  });
};

我不建议使用promises,它们比原始回调慢。你根本不需要它们。

link1 - SIGINT
link2 - db wrapper