调用require时,我似乎得到一个“新的模块实例”

我试图让MongoDB与Express.js一起工作。 我遵循这篇文章,并创build了一个文件db/index.js ,它提供了创build数据库连接和返回连接实例的function。 在app.js我首先需要该文件,然后调用它的函数connect ,它成功连接到数据库。

但是,当我需要文件db/index.js在另一个文件routes/users.js ,它返回的数据库引用是null ,虽然我期望它是我在app.js连接时得到的相同引用。 require总是返回第一次调用返回的模块的同一个实例吗? 我究竟做错了什么?

编辑:我明白,因为调用db.connect是asynchronous的, users.jsdb值可能在连接函数返回之前理论上是null的。 不过,我已经通过testing进行了validation,即使连接已成功创build,当我对path / users执行POST请求时, db仍然为null

这里是3个相关的文件。

app.js (执行从这里开始)

 var express = require('express'); var path = require('path'); var favicon = require('serve-favicon'); var logger = require('morgan'); var cookieParser = require('cookie-parser'); var bodyParser = require('body-parser'); // configuration environment based on process.env.NODE_ENV environment variable var config = require('./config'); var db = require('./db'); var app = express(); var routes = require('./routes/index'); var users = require('./routes/users'); app.use('/', routes); app.use('/users', users); // Connect to Mongo on start db.connect(config.dbUrl, function (err) { if (err) { console.log('Unable to connect to ' + config.dbUrl); process.exit(1); } else { console.log('Connected to ' + config.dbUrl); } }); // view engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'jade'); // uncomment after placing your favicon in /public //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); app.use(logger('dev')); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({extended: false})); app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); app.use('/tests', express.static(__dirname + '/test')); app.use('/lib/jasmine-core', express.static(__dirname + '/node_modules/jasmine-core/lib/jasmine-core')); // catch 404 and forward to error handler app.use(function (req, res, next) { var err = new Error('Not Found'); err.status = 404; next(err); }); // error handlers // development error handler // will print stacktrace if (app.get('env') === 'development') { app.use(function (err, req, res, next) { res.status(err.status || 500); res.render('error', { message: err.message, error: err }); }); } // production error handler // no stacktraces leaked to user app.use(function (err, req, res, next) { res.status(err.status || 500); res.render('error', { message: err.message, error: {} }); }); module.exports = app; 

DB / index.js

 var MongoClient = require('mongodb').MongoClient; var state = { db: null }; exports.connect = function (url, done) { if (state.db) return done(); MongoClient.connect(url, function (err, db) { if (err) return done(err); state.db = db; done(); }) } exports.get = function () { return state.db; } exports.close = function (done) { console.log('db close'); if (state.db) { state.db.close(function (err, result) { state.db = null; done(err); }) } } exports.createIndexes = function () { if (state.db) { state.db.collection('events').createIndex( {'id': 1}, {unique: true}); } } 

路线/ users.js

 var express = require('express'); var router = express.Router(); var db = require('../db').get(); router.post('/', function (req, res, next) { // // Problem: Every time this function is called, db is null! // var users = db.collection('users'); var userToAdd = req.body; users.findOne({username: userToAdd.username}).then(function (foundUser) { if (foundUser.length === 0) { res.status(400).json({error: 'Username is already in use'}); } else { // TODO: ADD USER res.json(foundUser); } }) .catch(function (err) { console.log(err); res.status(500).json({error: 'Database error.'}); }); }); module.exports = router; 

为了logging,你没有收到“新”的实例,下面的解释将帮助你理解正在发生的事情。

请注意,在通过db.connect连接到db之前,您需要路由。 即

 //Called before db.connect is called. //so at this point in time, your db.get will return null, make sense? //because in your users.js your are directly calling var db = require('../db').get(); var routes = require('./routes/index'); var users = require('./routes/users'); app.use('/', routes); app.use('/users', users); // Connect to Mongo on start db.connect(config.dbUrl, function (err) { if (err) { console.log('Unable to connect to ' + config.dbUrl); process.exit(1); } else { //after this point in execution, calling db.get will return actual db and not null. console.log('Connected to ' + config.dbUrl); } }); 

有两个解决您的问题。

1。

像这样重构你的app.js代码将解决你的问题。

 // Connect to Mongo on start db.connect(config.dbUrl, function (err) { if (err) { console.log('Unable to connect to ' + config.dbUrl); process.exit(1); } else { //As now we have db initialised, lets load routes. var routes = require('./routes/index'); var users = require('./routes/users'); app.use('/', routes); app.use('/users', users); console.log('Connected to ' + config.dbUrl); } }); 

2

把你的app.js保持原样,然后改变你的路线,例如users.js使用db作为如下,

 var express = require('express'); var router = express.Router(); var dbFetcher = require('../db'); router.post('/', function (req, res, next) { // // Problem: Every time this function is called, db is null! var db = dbFetcher.get(); var users = db.collection('users'); var userToAdd = req.body; users.findOne({username: userToAdd.username}).then(function (foundUser) { if (foundUser.length === 0) { res.status(400).json({error: 'Username is already in use'}); } else { // TODO: ADD USER res.json(foundUser); } }) .catch(function (err) { console.log(err); res.status(500).json({error: 'Database error.'}); }); }); module.exports = router; 

我希望这是有道理的,并帮助!

var db = require('./db'); 声明一个只存在于该文件范围内的新variables。 当你在你的routes / user文件中做类似的声明时,你会创build一个全新的dbvariables,这意味着connect方法从不运行,所以state属性从来没有改变过。