node.js - Node.js Express 中的异步代码

标签 node.js express asynchronous

我正在尝试使用 Node.js Express 创建 MVC 模式,但在执行异步代码时这似乎是一项完全不可能完成的任务。

恰当的例子:我正在从模型中的 NeDB 数据库中获取结果,如下所示:

controllers/database.js

// Database management stuff with NeDB
var data = {};
db.findOne({ _id: 1 }, (error, doc) => {
    if (error) console.error(error);
    data = doc;
}

现在,我将在名为 dbcontroller.js 的 Controller 中使用它:

var nedb = require('../models/nedb.js');

module.exports.list = function(req, res, next) {
    res.render('listpage', {
        data: nedb.data,
    });

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;

可爱的安排,不是吗? 现在,可以肯定的是,NeDB findOne() 函数是异步的,所以它将在 module.exports 之后执行,但这是行不通的。想到的解决方案当然是将 module.exports 定义放在 findOne() 回调中!

db.findOne({ _id: 1 }, (error, doc) => {
    if (error) console.error(error);
    module.exports.data = data;
}

我确定这是某个地方的反模式,但它确实有效。或者是吗?真正的戏剧现在开始。

当它被 Controller 调用时,findOne() 函数也会在所有 Controller 逻辑之后完成,这意味着 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();
    });
}

dbcontroller.js:

nedb.execute(export);

function export() {
    module.exports.list = function(req, res, next) {
        res.render('listpage', {
            data: nedb.data,
        });
    };
};

而且情况变得更糟。routes.js 文件现在找不到 dbcontroller.list,大概是因为它仍然定义在 之后路线要求它。现在,我是否也必须开始将路由定义放入回调中?

我的观点是,整个异步性似乎完全占据了我的代码结构。以前整洁的代码现在变得一团糟,因为我无法将代码放在它所属的位置。这只是 一个 异步函数,NeDB 有很多异步函数,虽然这很好,但如果 findOne() 已经让我头疼了,我不知道我是否能处理它。

也许我真的别无选择,我必须弄乱我的代码才能让它工作?或者也许我错过了一些非常基本的东西?或者像 async 或 promises 这样的库可以满足我的需求?你怎么看?

最佳答案

为了让异步代码工作,您需要通过回调、 promise 或其他方式通知您何时完成。要使上面的示例正常工作,您需要做的就是调用 res.render after 您确定 data 已定义。为此,您可以从数据库提取中返回一个 promise ,或将其传递给回调。我会建议 promise ,因为它们更容易使用,因为它们有助于避免 "callback hell" ,并且 Node 长期以来一直对它们提供原生支持。

controllers/database.js

module.exports.fetch = function() {
  return new Promise(function(resolve, reject) {
    db.findOne({ _id: 1 }, (error, doc) => {
      if (error) reject(error);
      resolve(doc);
   });
}

然后,在您的 Controller 中,您只需在呈现响应之前调用 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 */ });
}

要记住的是,express 并不期望您立即调用 res.render。您可以执行大量异步代码,然后在完成后呈现响应。

关于node.js - Node.js Express 中的异步代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39708902/

相关文章:

ruby-on-rails - 实时聊天应用程序使用什么

node.js - ExpressJS 上的子域

javascript - 有没有办法匹配 npm 链接的项目 git 分支?

node.js - Express 中的数据库查询错误 : Router. use() 需要一个中间件函数,但得到一个未定义的

javascript - NodeJS中的Module.exports,输出函数

node.js - Express 4/Node JS - 优雅地管理 uncaughtException

javascript - JWT 不解码 "JWT malformed"- Node Angular

c# - 使用 async/await/TPL 的这两个函数有什么区别?

node.js - 是否需要在异步调用中嵌套异步调用? ( Node .js)

javascript - 为什么我的 async.waterfall javascript 顺序代码没有结束?