然后是Promise.all没有执行

时间:2018-02-15 07:04:05

标签: node.js promise google-cloud-firestore

我正在使用firestore来检索具有以下DS的数据 我有一个 Company 集合,其中包含一个子集合分支
所以我正在尝试检索列出所有公司及其分支

代码:

exports.findAll = function (req, res) {
    getcompanies().
    then((companies) => {
        console.log("Main "+ companies) // info: Main TypeError: Cannot read property 'Symbol(Symbol.iterator)' of undefined
        return res.json(companies);
    })
    .catch((err) => {
        console.log('Error getting documents', err);
    });
}

function getCompanies(){
    var companiesRef = db.collection('companies');

    return companiesRef.get()
    .then((snapshot) => {
        let companies = [];
        return Promise.all(
            snapshot.forEach(doc => {  
                    let company = {};                
                    company.id = doc.id;
                    company.company = doc.data(); 
                    var branchesPromise = getBranchesForCompanyById(company.id);
                    return branchesPromise.then((branches) => {                    
                            company.branches = branches;
                            companies.push(company); 
                            if(snapshot.size === companies.length){
                                console.log("companies - Inside" + JSON.stringify(companies)); //This prints all companies with its branches
                            }
                            return Promise.resolve(companies);
                        })
                        .catch(err => {
                            console.log("Error getting sub-collection documents", err);
                            return Promise.reject(err);
                        }) 
            })
        )
        .then(companies => {
            console.log("Outside " + companies) // This is never executed 
            return companies;
        })
        .catch(err => {
            return err;
        });

    })
    .catch(err => {
        return err;
    });
}

function getBranchesForCompanyById(id){
    var branchesRef = db.collection('companies').doc(id).collection('branches');
    let branches = [];
    return branchesRef.get()
     .then(snapshot => {
        snapshot.forEach(brnch => {
            let branch = {};
            branch.id = brnch.id;
            branch.branch = brnch.data();
            branches.push(branch);
        })
        return branches;
    })
    .catch(err => {
        return err;
    })

 }

此时我需要的所有数据。

console.log("companies - Inside" + JSON.stringify(companies)); //This prints all companies with its branches

但Promise.all的时间永远不会被执行。所以得到这个错误 -

info:Main TypeError:无法读取未定义

的属性'Symbol(Symbol.iterator)'
console.log("Main "+ companies) // info: Main TypeError: Cannot read property 'Symbol(Symbol.iterator)' of undefined

我觉得我已遵循此处指定的所有规则:https://stackoverflow.com/a/31414472/2114024关于嵌套承诺,不确定我在哪里错过了这一点。
提前谢谢!

3 个答案:

答案 0 :(得分:1)

我发现至少有两个问题:

  • forEach可能无法返回任何内容,您将forEach的结果发送到Promise.all()
  • 如果Promise.all()抛出异常,您的一些catch处理程序只会获取错误并将其返回。返回它会把它变成一个非例外。

您也不必为每个Promise链添加catch,只要您将Promise链的结果反馈到另一个promise链中,您可能只需要1个catch块。

您的then()函数之一也不应该深深嵌套。只需将其提升一级,这就是承诺的重点。

答案 1 :(得分:1)

在您的代码中,您可以使用map而不是forEach。 Promise.all接受一组promise,但forEach不返回数组

return Promise.all(
    snapshot.map(doc => {
        let company = {};
        company.id = doc.id;
        company.company = doc.data();
        var branchesPromise = getBranchesForCompanyById(company.id);
        return branchesPromise.then((branches) => {
                company.branches = branches;
                companies.push(company);
                if (snapshot.size === companies.length) {
                    console.log("companies - Inside" + JSON.stringify(companies)); //This prints all companies with its branches
                }
                return Promise.resolve(companies);
            })
            .catch(err => {
                console.log("Error getting sub-collection documents", err);
                return Promise.reject(err);
            })
    })
)

答案 2 :(得分:0)

根据Evert和Rahul的意见,感谢你们两位,我已经解决了这个问题。

  1. 我处理了catch块中的所有错误
  2. Promise.all没有返回任何内容,因此我将forEach转换为map。
  3. 所以这是我更新的代码,它解决了这个问题:

    exports.findAll = function (req, res) {
        getcompanies().
            then((companies) => {
                console.log("Main " + companies) // Prints all companies with its branches
                return res.json(companies);
            })
            .catch((err) => {
                console.log('Error getting documents', err);
                return res.status(500).json({ message: "Error getting the all companies" + err });
            });
    }
    
    function getCompanies() {
        var companiesRef = db.collection('companies');
    
        return companiesRef.get()
            .then((snapshot) => {
                let companies = [];
                return Promise.all(
                    snapshot.docs.map(doc => {
                        let company = {};
                        company.id = doc.id;
                        company.company = doc.data();
                        var branchesPromise = getBranchesForCompanyById(company.id);
                        return branchesPromise.then((branches) => {
                            company.branches = branches;
                            companies.push(company);
                            if (snapshot.size === companies.length) {
                                console.log("companies - Inside" + JSON.stringify(companies));
                                return companies;
                            }
                        })
                            .catch(err => {
                                console.log("Error getting sub-collection documents", err);
                                throw new Error(err);
                            })
                    })
                )
                    .then(companies => {
                        console.log("Outside " + companies); // Executed now
                        return companies[companies.length - 1];
                    })
                    .catch(err => {
                        throw new Error(err);
                    });
    
            })
            .catch(err => {
                throw new Error(err);
            });
    }
    
    function getBranchesForCompanyById(id) {
        var branchesRef = db.collection('companies').doc(id).collection('branches');
        let branches = [];
        return branchesRef.get()
            .then(snapshot => {
                snapshot.forEach(brnch => {
                    let branch = {};
                    branch.id = brnch.id;
                    branch.branch = brnch.data();
                    branches.push(branch);
                })
                return branches;
            })
            .catch(err => {
                throw new Error(err);
            })
    
    }