【问题标题】:How to return promise to the router callback in NodeJS/ExpressJS如何在 NodeJS/ExpressJS 中向路由器回调返回 Promise
【发布时间】:2017-01-06 01:36:44
【问题描述】:

我是 nodejs/expressjs 和 mongodb 的新手。我正在尝试创建一个 API,将数据公开给我尝试使用 Ionic 框架构建的移动应用程序。

我有这样的路线设置

router.get('/api/jobs', (req, res) => {
  JobModel.getAllJobsAsync().then((jobs) => res.json(jobs)); //IS THIS THe CORRECT WAY?
});

我的模型中有一个从 Mongodb 读取数据的函数。我正在使用 Bluebird Promise 库将我的模型函数转换为返回 Promise。

const JobModel = Promise.promisifyAll(require('../models/Job'));

我在模型中的功能

static getAllJobs(cb) {

    MongoClient.connectAsync(utils.getConnectionString()).then((db) => {

      const jobs = db.collection('jobs');
      jobs.find().toArray((err, jobs) => {

        if(err) {
          return cb(err);
        }

        return cb(null, jobs);
      });
    });
  }

promisifyAll(myModule) 将此函数转换为返回一个 Promise。

我不确定的是,

  • 如果这是从我的模型将数据返回到路由回调函数的正确方法?
  • 这样有效吗?
  • 使用 promisifyAll 很慢?因为它循环遍历模块中的所有函数并创建一个以 Async 作为后缀的函数副本,该副本现在返回一个 Promise。它什么时候真正运行?这是一个与节点要求语句相关的更通用的问题。请参阅下一点。
  • 所有 require 语句何时运行?当我启动 nodejs 服务器时?或者当我调用 api 时?

【问题讨论】:

  • 看看猫鼬模块。
  • @Yahya 我研究过它。但我不想在我的文档上强制执行模式。
  • Monk 呢?
  • @Yahya - 我确实尝试过使用 mongojs。但是这些库并没有真正提供作为本机 mongod 的最新可用特性/功能,所以我正在尝试使用本机 mongod。

标签: node.js mongodb api express bluebird


【解决方案1】:

您的基本结构或多或少是正确的,尽管您对Promise.promisifyAll 的使用对我来说似乎很尴尬。对我来说,基本问题(这不是一个真正的问题——你的代码看起来可以工作)是你正在混合和匹配基于承诺和基于回调的异步代码。正如我所说,这应该仍然有效,但我宁愿尽可能坚持一个。

如果您的模型类是您的代码(而不是其他人编写的某个库),您可以轻松地将其重写为直接使用 Promise,而不是为回调编写它然后使用 Promise.promisifyAll把它包起来。

以下是我将如何处理getAllJobs 方法:

static getAllJobs() {

    // connect to the Mongo server
    return MongoClient.connectAsync(utils.getConnectionString())

        // ...then do something with the collection
        .then((db) => {
            // get the collection of jobs
            const jobs = db.collection('jobs');

            // I'm not that familiar with Mongo - I'm going to assume that
            // the call to `jobs.find().toArray()` is asynchronous and only 
            // available in the "callback flavored" form.

            // returning a new Promise here (in the `then` block) allows you
            // to add the results of the asynchronous call to the chain of
            // `then` handlers. The promise will be resolved (or rejected) 
            // when the results of the `job().find().toArray()` method are 
            // known
            return new Promise((resolve, reject) => {
                jobs.find().toArray((err, jobs) => {
                    if(err) {
                        reject(err);
                    }
                    resolve(jobs);
                });
            });
        });
}

此版本的getAllJobs 返回一个承诺,您可以将thencatch 处理程序链接到该承诺。例如:

JobModel.getAllJobs()

    .then((jobs) => {
        // this is the object passed into the `resolve` call in the callback
        // above. Do something interesting with it, like
        res.json(jobs);
    })

    .catch((err) => {
        // this is the error passed into the call to `reject` above
    });

诚然,这与您上面的代码非常相似。唯一的区别是我放弃了使用Promise.promisifyAll - 如果你自己编写代码并且你想使用promise,那就自己做吧。

一个重要提示:包含catch 处理程序是个好主意。如果你不这样做,你的错误将被吞并消失,你会想知道为什么你的代码不工作。即使您认为不需要它,也只需编写一个 catch 处理程序将其转储到 console.log。你会很高兴你做到了!

【讨论】:

  • 在阅读softwareengineering.stackexchange.com/a/279003 之前,我最初也做过同样的事情。所以我最终使用了这种方法。我还想了解每个模块顶部的 require 语句何时运行?我的问题的最后一部分。
  • 你能回复我吗?我被这个问题困住了。
  • 我的理解(仅基于我自己的非正式观察 - 我从未测试过)导入和要求是在加载模块时执行的。关于您在评论中发布的链接:我没有看到那个讨论 - 它表明使用这种方法性能会更好。这可能是真的,如果性能是您最关心的问题,那就去做吧。我在编写代码时通常会考虑其他几个问题:保持代码简单易读,除非需要,否则避免包含包。
  • 感谢您回来。虽然考虑到我只是为了学习,性能可能不是我现在正在开发的应用程序的主要关注点。但我的目标是了解正确和最好的方法。关于 nodejs/expressjs 中编码的任何其他改进/建议?这是我尝试使用 node 和 mongo 编写的第一个应用程序。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-04-27
  • 1970-01-01
  • 2021-07-11
  • 2021-09-16
  • 2021-09-25
  • 2021-10-30
  • 2020-01-16
相关资源
最近更新 更多