在递归,回归问题中,Mongoose中的承诺

时间:2018-01-23 15:55:39

标签: javascript json node.js mongoose promise

我正在努力应对Mongoose的承诺,因为我习惯于进行同步编程。

上下文

我有很多类别。每个类别都没有或有一个父类别。 知识与类别相关联。 我想创建一个包含所有类别及其子类别和知识的树。

enter image description here

实际上,它看起来像是具有目录文件的模型。 预期的输出就像JSON:

[
    {"name": "cat0",
     "children": [{"name": know0}]
    },
    {"name": "cat1",
    ...
]

代码

我使用递归方式。我用null调用函数(获取所有根类别),然后递归调用将应用于子类别。

static findKnowledgeByCategory(query = null){


    return new Promise((resolve, reject) => {
        CategoryModel.find({parent: query})
            .then((categories) => {
                console.log(query + ' : CategoryModel.find success');
                return new Promise((resolve, reject) => {
                    console.log(query + ' : new Promise');
                    categories.forEach(cat => { // cat == { _id: ..., parent: ..., name: 'smthng' }
                        KnowledgeModel.find({category: cat._id})
                            .then((knowledges) => {
                                console.log(query + ' : KnowledgeModel.find success');
                                cat.knowledges = knowledges;
                                Model.findKnowledgeByCategory(cat._id)
                                    .then((categories) =>{
                                        cat.children = categories;
                                    });
                            })
                    })
                }).then(() => {
                    console.log(query + ' : Début resolve');
                    return resolve(categories);
                })
            })
            .catch((err) =>{
                console.log(err);
                return reject();
            } )
    });

}

我必须使用此代码返回一个promise,因为在更全局的范围内,它的解析用于返回JSON中的树。

全球范围

findKnowledgeByCategory()
        .then((catAndKnow) => res.status(200).json(catAndKnow))
        .catch(err => Validation.handleError(res, 500, err));

没有显示错误,但是当我调用该函数时,服务器没有响应。

请注意,它永远不会显示“Débutresolution”... 我正在使用Node 6.11.2所以我不能使用“await”。 任何想法将不胜感激。如果我的问题不相关,我道歉。我想我没有很好地管理我的承诺,但我没有任何线索。

2 个答案:

答案 0 :(得分:1)

您不应该使用promise constructor anti-pattern。由于您的方法调用(如find)已经生成了promise,您应该返回附加到那些的promise链。

其次,保持你的嵌套:由于这个原因发明了承诺,所以不是嵌套then调用,而是尽快将承诺返回到外链,并链接then调用那里。

最后,当您在forEach内创建承诺时,您需要将这些承诺组合成一个承诺。 Promise.all只是解决这个问题的方法。因此,使用forEach代替map,在回调中返回promises,并将结果传递给Promise.all

以下是您的代码的外观(未经测试):

static findKnowledgeByCategory(query = null) {
    return CategoryModel.find({parent: query}).then((categories) => {
        console.log(query + ' : CategoryModel.find success');
        return Promise.all(categories.map(cat => {
            return KnowledgeModel.find({category: cat._id}).then((knowledges) => {
                console.log(query + ' : KnowledgeModel.find success');
                cat.knowledges = knowledges;
                return Model.findKnowledgeByCategory(cat._id);
            }).then((children) => {
                cat.children = children;
            });
        })).then(() => {
            console.log(query + ' : Début resolve');
            return categories;
        })
    });
}

答案 1 :(得分:0)

看一下代码的这一部分:

return new Promise((resolve, reject) => {
    console.log(query + ' : new Promise');
    categories.forEach(cat => { 
        KnowledgeModel.find({category: cat._id})
            .then((knowledges) => {
                console.log(query + ' : KnowledgeModel.find success');
                cat.knowledges = knowledges;
                Model.findKnowledgeByCategory(cat._id)
                .then((categories) =>{
                    cat.children = categories;
                });
        })
    })
})

您永远不会在此承诺中调用resolvereject,因此永远无法解决。尝试将代码拆分为更小的函数,返回promises,然后将它们排列在一起 - 捕获这样的情况要容易得多。