0

我在 MongoDB 中有这个集合(为简洁起见,我省略了_ids):

test> db.entries.find();
{
  "val": 1
}
{
  "val": 2
}
{
  "val": 3
}
{
  "val": 4
}
{
  "val": 5
}

我需要对每个我无法处理的文档进行一些处理db.update()。因此,简而言之,我需要做的是一次检索一个文档,在 Node 中处理它并将其保存回 Mongo。

我正在使用 Monk 库,并使用 Q 表示承诺。这是我所做的——为简洁起见,我没有包括处理/保存位:

var q = require('q');

var db = require('monk')('localhost/test');
var entries = db.get('entries');

var i = 1;
var total;

var f = function (entry) {
    console.log('i = ' + i);
    console.log(entry.val);
    i++;
    if (i <= total) {
        var promise = entries.findOne({ val: i });
        loop.then(function (p) {
            return f(p);
        });
        return promise;
    }
};

var loop = q.fcall(function () {

    return entries.count({});

}).then(function (r) {

    total = r;
    return entries.findOne({ val: i });

}).then(f);

我希望这段代码能打印出来:

i = 1
1
i = 2
2
i = 3
3
i = 4
4
i = 5
5

但它实际上打印出来:

i = 1
1
i = 2
2
i = 3
2
i = 4
2
i = 5
2

我究竟做错了什么?

4

1 回答 1

1

在您的代码中,循环是唯一的一个承诺。它只执行一次。它不是一个函数。在内部floop.then(f)只需使用 promise 的结果触发f(它已经执行,因此不会再次执行)。

你实际上想要创建几个 Promise。您正在寻找的东西应该是这样的:

var q = require('q');

var db = require('monk')('localhost/test');
var entries = db.get('entries');

var i = 1;
var total;

var f = function (entry) {
    console.log('i = ' + i);
    console.log(entry.val);
    i++;
    if (i <= total) {
        // I am not sure why you put entries.findOne here (looks like a mistake, 
        // its returned value isn't used) but if you really need it to be done
        // before loop, then you must pipe it before loop
        return entries.findOne({ val: i }).then(loop);
        // do not pipe f again here, it is already appended at the end of loop
    }
};

function loop(){
    return q.fcall(function () {
        return entries.count({});
    }).then(function (r) {
        total = r;
        return entries.findOne({ val: i });
    }).then(f);
}

loop();

如果你有兴趣,这里有一篇关于 promises 的非常好的文章

于 2015-08-30T20:49:17.877 回答