关于mongoose结合promise的问题
发布于 9 年前 作者 jimmyyao88 9266 次浏览 最后一次编辑是 8 年前 来自 问答

最近被回调地狱弄的有点恶心 所以准备用promise来优化一下 mongoose本身的exec方法会返回promise 比如: User.findOne({_id:id}).populate('posts').exec()本身就会返回promise . 但是我在最后的回调中想用到之前所哟回调里拿到的数据该怎么做呢 比如:

	promise.then( function(user){
		//这里拿到了user
		return  Post.find(user).populate(XXX).exec( )
	} ).then(function(post){
		//这里拿到了post
		return Video.find(post).populate(XXX).exec()
	}).then(function(video){
	//在这里最后的回调中 想获得前面回调里面得到的user 和post   该怎么做呢??
	res.render({
			user:user,
			post:post,
			video:video
		})
	})
`` 
最后的回调中 想获得前面回调里面得到的user 和post   该怎么做呢??
尝试了一下bluebird 但是似乎不能用来写成Post.findAsync(user).populate(XXX).exec( )这种形式
怎么解决呢 求大神支招
13 回复

Mongoose自带的promise 不好用吧, 建议用bluebird

@pangguoming 额 你好这个bluebird 的确在用 尝试了一下bluebird 但是似乎不能用来写成Post.findAsync(user).populate(XXX).exec( ).then(…)这种形式

这个貌似没什么好的方案吧,放外部变量呗

asyncwaterfall能传递参数,但是,你还是照着 @luoyjx 的方法来吧,我后面都用这种方法了,现在用async只是规范一下代码了。

其实bluebird好像也只能放外部变量吧。。。

把 user 和 post 包进一个 Object 里面如何?

@infinite-sky 哦哦 谢谢了

@jimmyyao88 不想放外部也可以,就是得每次都将变量传递下去,不过好像也麻烦

一般promise都配合generator使用,会方便很多。 如下代码,你参考下: 这里使用co库

'use strict';

let fs = require('fs');
let co = require('co');

function readFile(filename) {
  return new Promise(function (resolve, reject) {
    fs.readFile(filename, 'utf-8', function (err, content) {
      if (err) {
        reject(err);
      } else {
        resolve(content);
      }
    });
  });
}

co(function *() {
  let file1 = yield readFile('./1.txt');
  let file2 = yield readFile('./2.txt');
  let file3 = yield readFile('./3.txt');

  // 这里处理file1, file2, file3
  console.log(file1);
  console.log(file2);
  console.log(file3);

}).catch(function (err) {
  console.error(err.stack);
});

自己实现了一个简易的co方法,仅供参考

'use strict';

let fs = require('fs');

function readFile(filename) {
  return new Promise(function (resolve, reject) {
    fs.readFile(filename, 'utf-8', function (err, content) {
      if (err) {
        reject(err);
      } else {
        resolve(content);
      }
    });
  });
}

let gen = function *() {
  let file1 = yield readFile('./1.txt');
  let file2 = yield readFile('./2.txt');
  let file3 = yield readFile('./3.txt');

  // 这里处理file1, file2, file3
  console.log(file1);
  console.log(file2);
  console.log(file3);
}

function run(gen) {
  let iterator = gen();

  next(iterator.next());

  function next(result) {
    if (result.done) {
      return result.value;
    }
    return result.value.then(function (value) {
      next(iterator.next(value));
    });
  }
}

run(gen);

untitled1.png

你的代码 我这么改造了下,你看看:

'use strict';

co(function *() {
  let user = yield User.findOne({_id: id}).populate('posts').exec();
  let post = yield Post.find(user).populate(XXX).exec();
  let video = yield Video.find(post).populate(XXX).exec();

  // 这里你可以处理user,post,video
  res.render({
    user: user,
    post: post,
    video: video
  })
}).catch(function (err) {
  console.error(err.stack);
});

```

如果还用promise的话, 可以这么干 .

//增加一个result, 来hold住结果.
var result = {};
promise.then( function(user){
        //这里拿到了user
		result.user = user;
        return  Post.find(user).populate(XXX).exec( )
    } ).then(function(post){
        //这里拿到了post
		result.post = post;
        return Video.find(post).populate(XXX).exec()
    }).then(function(video){
    //在这里最后的回调中 想获得前面回调里面得到的user 和post   该怎么做呢??
	 res.render({
            user:result.user,
            post:result.post,
            video:video
        })
    })

测试 自豪地采用 CNodeJS ionic

回到顶部