尝试进行嵌套查询时已调用节点异步回调

Posted

技术标签:

【中文标题】尝试进行嵌套查询时已调用节点异步回调【英文标题】:Node async callback was already called when trying to make a nested query 【发布时间】:2016-10-23 01:27:25 【问题描述】:

我在尝试使用 MEAN 堆栈进行异步查询时收到 Callback was already called 错误。我需要第二个回调仅在嵌套查询完成后触发(根据代码中的 cmets)。为什么会出现此错误?

路线示例:

router.route('/teams/:user_id').get(function (req, res) 

TeamProfile.find(
    Members : 
        $in : [req.params.user_id]
    
).exec(function (err, teamProfiles) 

    var asyncTasks = [];

    teamProfiles.forEach(function (teamProfile) 
        asyncTasks.push(function (callback) 
            UserProfile.find(
                UserID : 
                    $in : teamProfile.Members.map(function (id) 
                        return id;
                    )
                
            , function (err, userProfiles) 
                teamProfile.Members = userProfiles;
                callback();
            )
        );
    );

    teamProfiles.forEach(function (teamProfile) 
        asyncTasks.push(function (callback) 
            Draft.find(
                _id : 
                    $in : teamProfile.Drafts.map(function (id) 
                        return id;
                    )
                
            , function (err, drafts) 
                teamProfile.Drafts = drafts;

                drafts.forEach(function (draft) 
                    Comment.find(
                        _id : 
                            $in : draft.Comments.map(function (id) 
                                return id;
                            )
                        
                    ).exec(function (err, comments) 
                        draft.Comments = comments;
                        callback();
                        //This is where the callback should be called
                        //Throws Error: Callback was already called.
                    )                      
                )

            )
        );
    );

    async.parallel(asyncTasks, function () 
        res.json(teamProfiles)
    );
);
)

我正在使用async.parallel() 来执行所有查询。我对这一切都很陌生,所以请原谅一些初学者的错误。

【问题讨论】:

【参考方案1】:

您正在同步迭代 drafts 并在第一项上调用 async 的 callback 函数。当您尝试使用第二个项目再次调用它时出现错误是预期的行为。

您应该在完成所有草稿查询后调用 done 回调,而不是每个查询。由于您使用的是异步,您可以嵌套另一个 async.each 来处理此问题:

router.route('/teams/:user_id').get(function (req, res) 

        TeamProfile.find(
            Members : 
                $in : [req.params.user_id]
            
        ).exec(function (err, teamProfiles) 

            var asyncTasks = [];

            teamProfiles.forEach(function (teamProfile) 

                asyncTasks.push(function (callback) 
                    UserProfile.find(
                        UserID : 
                            $in : teamProfile.Members.map(function (id) 
                                return id;
                            )
                        
                    , function (err, userProfiles) 
                        teamProfile.Members = userProfiles;
                        callback();
                    );
                );
            );

            teamProfiles.forEach(function (teamProfile) 
                asyncTasks.push(function (callback) 
                    Draft.find(
                        _id : 
                            $in : teamProfile.Drafts.map(function (id) 
                                return id;
                            )
                        
                    , function (err, drafts) 
                        teamProfile.Drafts = drafts;

                        async.each(drafts, function(draft, draftCallback)

                            Comment.find(
                                _id : 
                                    $in : draft.Comments.map(function (id) 
                                        return id;
                                    )
                                
                            ).exec(function (err, comments) 
                                draft.Comments = comments;
                                draftCallback();
                            );

                        , function(err)
                            callback();
                        );
                    );
                );
            );

            async.parallel(asyncTasks, function () 
                res.json(teamProfiles)
            );
        );
    );

【讨论】:

感谢您的解释和回答。它完美地工作:)

以上是关于尝试进行嵌套查询时已调用节点异步回调的主要内容,如果未能解决你的问题,请参考以下文章

如何处理一对多关系中的嵌套 mongoose 查询和异步问题?

Firebase - for循环回调中的嵌套observeSingleEvent查询太多时间更新

从 Firebase 中的嵌套查询填充回收站视图

没有回调成功函数的嵌套 AJAX 请求

我可以从 Relay 查询结果中提取深度嵌套的节点吗?

nodejs Async 使用方法(解决多层回调嵌套)