.then 的 Promise.all 没有执行

Posted

技术标签:

【中文标题】.then 的 Promise.all 没有执行【英文标题】:.then of Promise.all not executing 【发布时间】:2018-07-25 21:01:06 【问题描述】:

我正在使用 Firestore 检索具有以下 DS 的数据。 我有一个 Company 集合,其中包含一个子集合 Branches 所以我试图检索列出所有 Companies 及其 Branches

代码:

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 的 then 永远不会被执行。所以得到这个错误 -

info: Main TypeError: Cannot read property 'Symbol(Symbol.iterator)' of undefined

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

我觉得我已经遵循了这里指定的所有规则:https://***.com/a/31414472/2114024 关于嵌套承诺,不知道我在哪里漏掉了重点。 提前致谢!

【问题讨论】:

【参考方案1】:

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

    我处理了 catch 块中的所有错误 Promise.all 没有返回任何内容,因此我将 forEach 转换为 map。

所以这是我更新的代码,它解决了问题:

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);
        )


【讨论】:

SO 应该允许您接受自己的答案。这样做是完全可以接受的。【参考方案2】:

在您的代码中,您可以使用 map 而不是 forEach。 Promise.all 接受一个承诺数组,但 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);
            )
    )
)

【讨论】:

我试过了,我认为,快照不支持地图。会再试一次看看。谢谢! 不需要返回 Promise.resolve(companies);您可以直接返回公司【参考方案3】:

我发现至少有 2 个问题:

forEach 可能不会返回任何内容,您将 forEach 的结果发送到 Promise.all()。 如果 Promise.all() 抛出异常,您的一些 catch 处理程序只会抓取错误并返回它。归还它会将其变为非异常。

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

您的then() 函数之一也不应该嵌套得那么深。只需将其提升一个级别,这就是承诺的意义所在。

【讨论】:

感谢您的意见。我已经更新了问题,我得到了一个 -info: Main TypeError: Cannot read property 'Symbol(Symbol.iterator)' of undefined。我仍然会根据您的输入重构代码。再次感谢! _你也真的不必为每一个 Promise 链添加一个 catch,只要你将一个 Promise 链的结果反馈给另一个 Promise 链,你可能只需要 1 个 catch 块_回复为此:Firestore 强制处理每个 promise 调用。 如果你在后面有一个 catch 块,你仍然会处理每个 promise 调用。我绝对同意每个 Promise 链必须有一个 catch 块,但只要你不断返回 Promise 的结果,你最终只需要一个。这绝对是可能的情况之一。;

以上是关于.then 的 Promise.all 没有执行的主要内容,如果未能解决你的问题,请参考以下文章

React Native 为啥我的代码在完成任务之前执行? Promise.all().then() 异步问题

.then() 在嵌套的 promise.all 和 fetch 完成之前执行

Promise.all().then() 解决?

使用 Promise.all() 在 Promise 实现时执行操作

备忘录Promise.all包含rejected状态的多个promise完成后执行事件

promise.all 怎么用