承诺返回值和嵌套

时间:2014-01-29 16:57:55

标签: javascript node.js asynchronous promise q

我有一个函数createOne()应该尝试查找MongoDB文档,或者如果找不到它就创建它。无论哪种方式,都应该返回一个承诺,并使用doc解决承诺:

var createOne = function(category) {
    var self = this;

    return this.findOne({ slug: category.slug }).exec()
        .then(function(doc) {
            if (!doc) {                    
                return self.create(category); // wait to resolve until document created.
            }
        });
};

findOne().exec()create()(应该)都会返回一个承诺。

我尝试了许多不同的方法,例如使用Q.fcall,使用Q.defer()和其他方法手动创建一个,但是缺少解析值,或者尽管创建了第二个{ slug: 'foo' }第一个已经存在(?)。

以下是我的主叫代码:

var data = [
    { slug: 'foo' },
    { slug: 'bar' },
    { slug: 'foo' } // <- shouldn't be created because of first 'foo'.
];

Q.fcall(function() {
    // [...]
}).then(function() {
    var promises = data.map(function(category) {
        return createOne(category); // <- calls createOne().
    });
    return Q.all(promises);
}).then(function(categories) {
    console.log(categories);
}).done();

如何构建createOne()以便console.log(categories)返回文档,无论是首先找到还是创建文档?

编辑:当集合为空时,只应创建两个文档。 { slug: 'foo' }只有一次。

1 个答案:

答案 0 :(得分:1)

似乎我已经想出了如何顺序调用异步函数并组成所有promise(以及后来解析的值)的最终数组。

我的解决方案基于我在Github的comment from kriskowal中找到的一个很棒的array.reduce示例。

var data = [
    'Element 1', 'Element 2', 'Element 3'
];

function asyncMock(element) {
    console.log('Handle', element);
    return Q.delay(element + ' handled.', 500);
}

var promise = data.reduce(function (results, element) {
    return results.then(function (results) {
        return asyncMock(element).then(function(result) {
            results.push(result);
            return results;
        });
    });
}, Q([]));

promise.then(function(elements) {
    console.log('Finished:', elements);
}).done();

您可以在此处找到有效的演示:http://jsfiddle.net/Lnvu4/