链接猫鼬承诺的语法

Posted

技术标签:

【中文标题】链接猫鼬承诺的语法【英文标题】:Syntax for chaining mongoose promises 【发布时间】:2018-09-01 07:36:51 【问题描述】:

我对使用 Promises 和 MongoDB / Mongoose 比较陌生,我正在尝试将多个数据库查询的流程链接成一个高效可靠的函数。

我想知道我的最终功能是否是实现我想要的良好且可靠的方法,或者是否存在任何问题或可以进行的任何改进。

流程如下:

1) 检查用户是否已经存在

usersSchema.findOne(
    email: email
).then(res => 
    if(res==null)
        // user does not exist
    
).catch(err => );

2) 将新用户添加到数据库中

var new_user = new usersSchema( email: email );
new_user.save().then(res => 
    // new user id is res._id
).catch(err => );

3) 为用户分配一个免费的促销代码

codeSchema.findOneAndUpdate(
    used: false,
    user_id: true
,
    used: true,
    user_id: mongoose.Types.ObjectId(res._id)
).then(res => 
    // user's code is res.code
).catch(err => );

显然,每个查询都需要按顺序执行,因此在对如何执行此操作进行了大量研究和实验后,我将查询组合成以下函数,目前看来工作正常:

function signup(email)
    // check email isn't already signed up
    return usersSchema.findOne(
        email: email
    ).then(res => 
        if(res==null)
            // add to schema
            var new_user = new usersSchema( email: email );
            // insert new user
            return new_user.save().then(res => 
                var result = parse_result(res);
                // assign a code
                return codesSchema.findOneAndUpdate(
                    used: false,
                    user_id: true
                ,
                    used: true,
                    user_id: mongoose.Types.ObjectId(result._id),
                );
            );
        else
            return 'The user already exists';
        
    );


signup('test@test.com').then(res => 
    console.log('success, your code is '+res.code);
).catch(err => 
    console.log(err);
);

我仍在努力弄清楚它是如何工作以及为什么工作的 - 函数正在返回一个承诺,每个嵌套的承诺都在返回一个承诺。

我主要担心的是存在大量嵌套(是否有办法通过链接 .then() 回调而不是嵌套所有内容来做到这一点?)并且嵌套的 Promise 似乎没有错误捕获,尽管由于 signup() 函数本身是一个承诺,这似乎捕获了所有错误。

是否有任何了解该主题的人能够确认我的流程看起来是否良好和可靠?谢谢!

【问题讨论】:

【参考方案1】:

为了避免缩进,如果你从传递给 Promise 的 .then() 方法的函数返回一个值,你可以将多个 .then() 链接成一个整洁的管道。请注意,您也可以返回一个具有待处理状态的 Promise,然后在它解决后执行下一个函数。

function signup (email) 
  return usersSchema.findOne(
    email: email
  ).then(res => 
    if (res) throw 'The user already exists'
    var new_user = new usersSchema( email: email )
    return new_user.save()
  ).then(res => 
    var result = parse_result(res)
    return codesSchema.findOneAndUpdate(
      used: false,
      user_id: true
    ,
      used: true,
      user_id: mongoose.Types.ObjectId(result._id)
    )
  )

更好的是,如果你有可能使用async/await(Node v7.6 或更高版本),你的代码看起来就像普通的阻塞代码:

async function signup (email) 
  let user = await usersSchema.findOne( email: email )
  if (user) throw 'The user already exists'
  let new_user = await new usersSchema( email: email ).save()
  let result = parse_result(new_user)
  return codesSchema.findOneAndUpdate(
    used: false,
    user_id: true
  ,
    used: true,
    user_id: mongoose.Types.ObjectId(result._id)
  )

您的原始函数调用代码无需更改即可在两者上运行。

【讨论】:

谢谢,这些都是很好的例子!我以前玩过 async/await,但这有助于澄清它的用途!【参考方案2】:

你的代码可以这样改进

function signup(email)
    // check email isn't already signed up
    return usersSchema.findOne(
        email: email
    ).then(res => 
        if(res==null)            // add to schema
            var new_user = new usersSchema( email: email );
            // insert new user
            return new_user.save()
        else
            return Promise.reject(new Error('The user already exists'));
        
    )
    .then(res => 
        var result = parse_result(res);
        // assign a code
        return codesSchema.findOneAndUpdate(used: false,user_id: true,used: true,user_id: mongoose.Types.ObjectId(result._id),);
    );



signup('test@test.com').then(res => 
    console.log('success, your code is '+res.code);
).catch(err => 
    console.log(err);
);

【讨论】:

以上是关于链接猫鼬承诺的语法的主要内容,如果未能解决你的问题,请参考以下文章

猫鼬承诺和声纳

猫鼬静态方法返回一个蓝鸟承诺

猫鼬承诺和Q承诺

猫鼬承诺文档说查询不是承诺?

猫鼬承诺错误

猫鼬模型保存后返回承诺