承诺 - 蒙戈:无法敲定诺言

时间:2015-01-17 13:43:29

标签: javascript node.js mongodb promise

这是我正在处理的一段代码:它将reddit帖子保存到mongoDB集合中。

我正在使用promised-mongo

问题是当for循环完成并且所有数据都保存到数据库时,程序不会退出,它会继续执行任何操作,尽管在每个promised-mongo promise链的末尾调用了done()

    for (var i = 0; i< posts.length; i++) { 
        posts[i].done = false;
        DB.posts.findOne({
            "id" : posts[i].id // it's 'id', not mongo's '_id'
        })
        .then(function(i) {
            return function(doc){
                if(doc) {
                    console.log('skipping')
                } else {
                    DB.posts.insert(posts[i]).then(function() {
                        console.log(arguments);
                        nSaved++;
                    });
                }
            }
        }(i))
        .catch(function(){
            console.log(arguments)
        })
        .done();
    }

我做错了什么?

1 个答案:

答案 0 :(得分:3)

这里有一些问题:

  • 您正在for循环中创建多个承诺,但不跟踪它们
  • 你有DB.posts.insert创造了一个承诺,但你没有等待它

以相反的顺序解决它们:

如果你不回复DB.posts.insert创建的承诺,那么在完成之前将无法等待它。你需要退货:

return function(doc){
    if(doc) {
        console.log('skipping')
    } else {
        // here
        return DB.posts.insert(posts[i]).then(function() {
            console.log(arguments);
            nSaved++;
        });
    }
}

您还需要跟踪您正在创建的所有承诺,以便了解它们何时完成。一种简单的方法是使用.map()将它们映射到promises数组,然后使用Promise.all()等待它们。

假设posts是一个数组:

function ensurePost(post) {
    post.done = false;

    return DB.posts.findOne({
        "id" : post.id // it's 'id', not mongo's '_id'
    })
    .then(function(doc){
        if(doc) {
            console.log('skipping ' + post.id)
        } else {
            return DB.posts.insert(post).then(function() {
                console.log(arguments);
                nSaved++;
            });
        }
    })
    .catch(function(error){
        console.error('Error inserting', post.id, error);
    });
}

Promise.all(posts.map(ensurePost))
.done(function () {
    // all done. close the connection
});

这也消除了你那里那种令人不快的IIFE的需要。