mongoose 自带的 promise 问题???
发布于 8 年前 作者 THCloud 14273 次浏览 来自 问答

好吧其实是用标题吸引人的。。 前几天问过这个问题,当时没人回答,现在想好好说一下问题然后再咨询一次。 涉及到数据库的查询,有两个model,一个是username,一个是login,然后写的是login的注册,那提取出来login的username字段,在username的model里查是不是已经存在,如果存在,返回exist,如果不存在,那就执行username的add操作,然后login在执行add操作。如果后两步哪里断了,就返回failed,成功了返回success

如果是用callback写的话大约逻辑就是这样的 1.jpg

其中checkExist用的是count方法 username.count(query, callback)就这样 add用的就是create方法

然后我就查了下promise的写法,mongoose的官网提到,mongoose的query不是promise但是支持then方法,然后我就把username的export那些方法都加了return,这么写了一下 2.jpg 结果他第一步check到了exist,但是还是执行login的create操作了,我就纳闷如果不返回promise怎么还能往下继续执行,但是想想mongoose的query不是promise,这样可能也说的通,然后我就把第一步的return false改成了一个throw error

但是这样做的话,我怎么去记录这个返回的状态呢? 在这个function里用一个变量,然后再加一个then方法单独返回状态吗? 总之感觉还是新手,这里应该还是写的不太好,希望大大们能提供个更好看的写法,或者给我个promise在mongoose应用的demo

还有就是,实际用mongo shell 查表发现,username的add多了一个空的记录,我完全不知道这个是哪里来的 3.jpg 这个是哪里的问题?

还望大神们不吝解答 还有暂时没打算用bb,因为promise还没用好直接用bb总感觉没学会走就跑的感觉。。。

24 回复

刚才试了一下,catch后面加then也不好使 啊!他也不继续执行了啊

https://cnodejs.org/topic/571238a3434cfcfa52684ab9 参考这个项目解决 如果是非success的状态,直接在callback里用state new一个error过去 如果成了,就在callback的data传个success

但是数据库的两条记录没找到哪里的毛病。。

then 里面的return 并不是return下一步操作方法, then 是一定会返回一个promise, then的return传值的作用. 可以传递 promise 也可以传递其他值到下一个then中, 如果没有显示return的话默认是传递一个 undefined. 如果是return promise则能构成promise链. 所以你 then(function(data))这步, 是一定会接收到值的并且一定会执行的, 你可以判断 data === false 来进行后续操作. 如果要用promise, 最好将promise理解透不是绕过去, 不然还会有很多问题在后面. 两份很好的promise 文档: http://efe.baidu.com/blog/promises-anti-pattern/ http://liubin.org/promises-book/

username.addUsername(query) 与 login.create(newUser) 前面加 return 你不 return 是不会被纳入链中的。

@czing 我也是没想绕过去,还在想这个 但是这个没有显试return,传递undefined的话,我感觉应该让这个链就断掉可能更合适点(我原来理解的promise) 要不然中间某一步出不同结果,想让他断掉,我都要throw error,然后跳到catch么

@klesh 每一个都是return

4.jpg 改了一下代码 把username的无意义的封装都弃用了,然后利用callback再传state过去了

@THCloud 没有办法断掉, promise的缺点: 无法确定状态, 没办法知道执行到哪里了; 无法取消, 一旦执行, 除非 throw err 否则会执行到底; 还有就是错误捕获问题, 一不小心错误就会被吐掉.

@czing 讲道理,虽然第一次用promise这个,也看了bluebird那些,总感觉这个其实是个坑。。

@THCloud promise有坑的地方, lz上面的代码看着更像是把回调函数进行了链式编写, 没坑到点上. 多尝试下吧, 熟悉后应该会有不同的看法. 而且promise也只是救人于callback hell 的临时方案, 实在受不了可以投入async怀抱.

楼主,能不能不要截屏啊,cnodejs 的编辑器上面有个 i 字加圆圈的,有介绍 md 语法,你可以直接贴源码,改起来就容易多了。 不一定要 throw error, 我个人就不这么干。建议以下方式:

var P = require('bluebird');

P.resolve().then(function() {
  console.log('this will be executed because last one was resolved.')
  return P.reject(new P.OperationalError('Fuck'));
}).then(function() {
  console.log('this will never be executed due to previous rejection.')
}).error(function(err) {
  console.log('error handles all business logical errors(OperationalError).');
  console.log(' ', err);
}).catch(function(err) {
  console.log('catch handles all unexpected exception like IO/Network failures.')
}).then(function() {
  console.log('this will also be executed due to error/catch were handled properly.');
})

你的 login.create 还是没有 return 啊。这样 success 是发生在 login.create 完成之前的。 另外 bluebird 有 nodeify 方法呀,你应该这样写:

var P = require('bluebird');

username.count(query).then(count => {
  if (count > 0)
    return P.reject(new P.OperationalError('exists'));

  return login.create(query).then(() => 'success');
}).nodeify(callback)

@klesh 截图这么方便,况且我md都不熟,还要现查,哈哈

还有你写的我试过,也不知道是不是我写错了,到catch就停了后面的then就没执行了

至于bb,promise这个还没熟呢,以后再说吧

login这个create操作,你这一说好像是有毛病,我把return callback单独提取个then出来好了

@magicdawn 收藏了!!!Tks!

@czing 其实我理解的promise也就是处理这个callback的嵌套,链式的时候代码看上去能好看点 至于async的方案,是指bluebird还是es7? 我这es6啊7啊都一点也不懂0.0

@klesh bluebird的我也只是大约略看了一眼,这个如果promise的话应该怎么写?有demo可以参考吗?

很感谢各路大神们的回复 我会一一参考,其实打算在这里一步改到位,以后就不重构了 如果有更好的demo也望不吝赐教

Promise 是一种规范,bluebird 是 Promise 的具体实现,我上面写的代码是基于 bluebird 的,输出结果正如预期。至于 mongoose 我看了一下好像用的是 mpromise 库,这个可能实现有不一致的地方。

@klesh 昨天晚上想了想还是决定用一下bluebird,好的东西应该试试 谢谢指导 😊

mongoose从4.1.0开始支持第三方promise库了

mongoose.Promise = require('bluebird');

@ravenwang 似的,它本身也自带一个promise了

@klesh 下面这段代码跑不出来,提示.then().nodeify is not a function, 替换成asCallback也不行 中间添加.error方法也会报错

你确定是 bluebird 吗?这两个方法是 bluebird 提供的。 mongoose 自带的不一定有这两个函数。

@klesh 是用的bluebird,因为我没涉及到mongoose的时候,写了一个test的code,这两个方法都好使,error跟nodeify 但是涉及到mongoose的时候,这两个方法都提示 not a function

试过mongoose。promise = P,和 P。promiseifyAll都没什么效果

回到顶部