Raf*_*ael 4 asynchronous node.js express
我正在尝试使用Node.js Express创建MVC模式,但是在执行异步代码时,这似乎是一件不可能完成的任务。
举个例子:我正在从模型中的NeDB数据库中获取结果,如下所示:
控制器/database.js
// Database management stuff with NeDB
var data = {};
db.findOne({ _id: 1 }, (error, doc) => {
if (error) console.error(error);
data = doc;
}
Run Code Online (Sandbox Code Playgroud)
现在,我将在名为dbcontroller.js的控制器中使用它:
var nedb = require('../models/nedb.js');
module.exports.list = function(req, res, next) {
res.render('listpage', {
data: nedb.data,
});
Run Code Online (Sandbox Code Playgroud)
在routes / routes.js文件中:
var express = require('express');
var router = express.Router();
var dbcontroller = require('../controllers/dbcontroller.js');
// Other controllers...
router.get('/list', dbcontroller.list);
// Other route definitions...
module.exports = router;
Run Code Online (Sandbox Code Playgroud)
可爱的安排,不是吗?现在,可以肯定的是,NeDB findOne()函数是异步的,因此它将在module.exports之后执行,而不会执行。我想到的解决方案当然是将module.exports定义放入findOne()回调中!
db.findOne({ _id: 1 }, (error, doc) => {
if (error) console.error(error);
module.exports.data = data;
}
Run Code Online (Sandbox Code Playgroud)
我确定这在某处是反模式,但可以。还是呢?真正的戏从现在开始。
当控制器调用它时,findOne()函数也会在所有控制器逻辑之后完成,这意味着nedb.data将是未定义的。我现在必须做一些疯狂的特技...
database.js
module.exports.execute = function (callback) {
db.findOne({ _id: 1 }, (error, doc) =>
{
if (error) console.error(error);
module.exports.data = doc;
callback();
});
}
Run Code Online (Sandbox Code Playgroud)
dbcontroller.js:
nedb.execute(export);
function export() {
module.exports.list = function(req, res, next) {
res.render('listpage', {
data: nedb.data,
});
};
};
Run Code Online (Sandbox Code Playgroud)
而且情况变得更糟。现在,routes.js文件找不到dbcontroller.list,大概是因为它在路由请求之后仍然被定义。现在,我是否也必须开始将路由定义放入回调中?
我的观点是,整个异步性似乎完全取代了我的代码结构。以前整洁的代码现在变得很丑陋,因为我不能将代码放在它所属的位置。那只是一个异步函数,NeDB有很多异步函数,虽然很棒,但是我不知道如果findOne()已经让我头疼的话我是否可以处理它。
也许我真的没有选择,我必须弄乱我的代码以使其起作用?或者,也许我错过了一些基本的东西?也许像async或promises这样的库可以满足我的需求?你怎么看?
为了使异步代码正常工作,您需要通过回调,promise或其他方式通知您何时完成异步代码。为了使上面的示例起作用,您需要做的就是在确定定义res.render 之后调用data。为此,您可以从数据库获取中返回承诺,也可以将其传递给回调函数。我建议使用promise,因为它们更容易使用,因为它们有助于避免“回调地狱”,并且Node长期以来一直对此提供支持。
控制器/database.js
module.exports.fetch = function() {
return new Promise(function(resolve, reject) {
db.findOne({ _id: 1 }, (error, doc) => {
if (error) reject(error);
resolve(doc);
});
}
Run Code Online (Sandbox Code Playgroud)
然后,在控制器中,您只需要fetch在呈现响应之前调用(否则最终将定义数据库获取代码)。
dbcontroller.js
var nedb = require('../models/nedb.js');
module.exports.list = function(req, res, next) {
nedb.fetch().then((data) => {
res.render('listpage', {
data: nedb.data,
});
}).catch((err) => { /* handle db fetch error */ });
}
Run Code Online (Sandbox Code Playgroud)
要记住的事情是快递不希望您立即打电话res.render。您可以执行许多异步代码,然后在完成后呈现响应。
| 归档时间: |
|
| 查看次数: |
3752 次 |
| 最近记录: |