【问题标题】:Synchronous mongoose request同步猫鼬请求
【发布时间】:2017-05-31 07:51:07
【问题描述】:

是否可以在函数上下文中处理 db.model.find() 查询并不使用使用 callbacks 和 promise 和 mongoose 库检索结果?

我需要确定的是,如果在运行控制器的过程中存在某个用户,那么由于大量相同的操作(例如,与数据库的通信),我无法将当前范围最小化为​​回调。此外,我正在尝试在我的项目中实现 MVC 模型,因此,我想将帮助程序库(模块)保存在单独的文件中。这就是为什么我不想使用任何回调或承诺——它们会使一切变得更加复杂,甚至比已经发生的事情还要复杂。


例如,我应该如何重写以下代码才能成功执行(如果实际上可能的话)(您可以忽略登录模型和控制器 - 如果使用回调重写该代码,它们被写入表示复杂性) :

user.js 库

var db = require('./lib/db');

class User{
    constructor(id){ //get user by id
        var result = db.models.user.findOne({_id: id}); //unsupported syntax in real :(
        if(!result || result._id != _id)
            return false;
        else{
            this.userInfo = result;

            return result;
        }

    }
}

module.exports = User;

登录模式

var user = require('./lib/user')
var model = {};

model.checkUserLogged(function(req){
    if(!req.user.id || req.user.id == undefined)
        return false;

    if(!(this.user = new user(req.user.id)))
        return false;
    else
        return true;
});

module.exports = model;

登录控制器

var proxy = require('express').router();

proxy.all('/login', function(req, res){

    var model = require('./models/login');

    if(!model.checkUserLogged()){
        console.log('User is not logged in!');
        res.render('unlogged', model);
    }else{
        console.log('User exists in database!');
        res.render('logged_in', model);
    }

});

生成器函数/yields、async/await (es2017) 以及其他一切都可以用来解决问题而无需嵌套。

提前致谢。

【问题讨论】:

  • 仅供参考,async/await 不是 ES7 (ES2016) 的一部分。它将成为今年发布的 ES2017 的一部分。
  • 糟糕。感谢您的注意:) 我已经在问题文本中更正了它。

标签: node.js mongodb asynchronous mongoose ecmascript-2016


【解决方案1】:

有两点错误:

  • Mongoose 方法不能被同步调用(无论如何,同步调用数据库并不是一个好主意)。
  • async/await 和生成器都不能在 ES6 类的构造函数中使用。这在answer 中有解释。

如果您不想要嵌套代码,一个简单的选择可能是使用 async/await(目前在 Node.js 中使用标志可用,不推荐用于生产)。由于 Mongoose 方法返回 Promise,它们可以与 async/await 一起使用。

但正如我所说,你不能在构造函数中这样做,所以它必须在其他地方。

例如,您可以这样做:

var proxy = require('express').router();
var db = require('./lib/db');

proxy.all('/login', async function(req, res){
    const result = await db.models.user.findOne({_id: req.user.id}).exec();
    if (!result) {
        console.log('User is not logged in!');
        return res.render('unlogged');
    }
    res.render('logged_in');
});

【讨论】:

  • 我可以使用 async/await(我现在有最新的 node.js,我可以打开--harmony 标志)。好的,让我们承认,该代码不是位于构造函数中,而是位于类的其他位置(例如,在静态函数中)。请给我一个例子,说明如何使用 async/await (ES7) 重写它?
  • 如果在const result =...之后到console.log,它总是返回Promise { <pending> }。我怎样才能得到一个响应对象而不是那个,为什么它仍然(等待完成的那一刻)待处理
  • .exec() 返回一个 Promise,但使用 await 代码执行将不会继续,直到 Promise 被解决。你是否正确使用了 async/await?
  • 我想,是的。我已经改变了你的例子,在类内部定义了一个类似的方法:async getUserIdByEmailPassword(_email, _password){ if(!_email || !_password) return false; var db = this; const res = await db.models.user.findOne({email: _email, password: md5(_password)}).exec(); return res; } 它只是返回 Promise { } 就像 Promise 对象还没有解决(!?):c跨度>
  • “无论如何,同步完成对数据库的调用根本不是一个好主意”为什么?在许多情况下,您需要来自 DB 的数据,如果没有这些数据,您将无法继续执行程序逻辑。在同步数据库请求中,您什么都不做 - 只等到数据来自数据库。在异步情况下,您必须在每种情况下处理这种等待行为 - 大量无用的代码。在每个数据库访问中,您不需要仅从异步 moogose 设计强制执行的代码!!!
【解决方案2】:

老问题,但我想分享一个我在前几次搜索中没有看到的处理方法。

我想从模型中获取数据,运行一些逻辑并从该逻辑返回结果。我需要一个 Promise 包装器来围绕我对模型的调用。

下面是一个稍微抽象的函数,它需要一个模型来运行 mongoose/mongo 查询,以及几个参数来帮助它执行一些逻辑。然后它返回承诺或拒绝中预期的值。

export function promiseFunction(aField: string, aValue, model: Model<ADocument, {}>): Promise<aType> {
    return new Promise<string>((resolve, reject) => {
      model.findOne({[aField]: aValue}, (err, theDocument) => {
        if(err){
          reject(err.toString());
        } else {
          if(theDocument.someCheck === true){
            return(theDocument.matchingTypeField)
          } else {
            reject("there was an error of some type")
          }
        }
      });
    })    
}

【讨论】:

    猜你喜欢
    • 2015-06-19
    • 1970-01-01
    • 1970-01-01
    • 2021-12-04
    • 1970-01-01
    • 2019-09-13
    • 2019-10-12
    • 2017-03-01
    • 1970-01-01
    相关资源
    最近更新 更多