使用循环中的嵌套promise来控制流

时间:2017-09-05 03:15:10

标签: javascript jquery angularjs promise bluebird

我无法使用promises控制我的方法流程:

//FIND CHECKED OUT FILES
getCheckedOutFiles = function () {
    console.log('Get checked out files');
    var d = $q.defer();

    // Store final results and pass to then callback
    var checkedOutFiles = window.x = [];

    // Promise, returns collection with all sites 
    SiteService.getAllSites()
        .then(sites => {
            // For each site get lists then get items matching filter
            sites.forEach(function (site) {
                var web = new $pnp.Web(site.url);

                return web.lists
                    .filter("BaseTemplate eq 101")
                    .get() // Returns promise with all lists matching filter 
                    .then(lists => {
                        // Go through each list and find matching item 
                        lists.forEach(function (list) {
                            web.lists.getByTitle(list.Title).items
                                .filter("CheckoutUser ne null")
                                .expand("File, File/Author, File/ModifiedBy, File/CheckedOutByUser")
                                .get() // Returns promise with all items matching filter 
                                .then(files => {
                                    // Loop through each item, get properties, add to collection 
                                    files.forEach(function (f) {
                                        var fileObject = {
                                            fileName: f.File.Name,
                                            fileUrl: f.File.ServerRelativeUrl,
                                            absoluteUrl: f.File.ServerRelativeUrl,
                                            checkedTo: f.File.CheckedOutByUser.Title,
                                            modified: f.Modified,
                                            modifiedBy: f.File.ModifiedBy.Title,
                                            createdBy: f.File.Author.Title,
                                            created: f.Created,
                                            version: f.File.UIVersionLabel
                                        };
                                        // Add file to collection 
                                        checkedOutFiles.push(fileObject);
                                    }, this);
                                })
                                .catch(e => {
                                    console.log(e);
                                });
                        });
                        // "Ideally" - When all files retrieved return collection of results 
                        d.resolve(checkedOutFiles);
                        return null;
                    })
                    .catch(e => {
                        console.log(e);
                    });
            }, this);
            return null;
        });
    return d.promise;
};

// Returns promise with all checkedout file 
getCheckedOutFiles().then(files => {
    console.log("RESULTS", files);
    d.resolve(files);
});

我注意到console.log("RESULTS", files);会在通话结束前打印出来。完成调用后,window.x将包含预期的数据。

2 个答案:

答案 0 :(得分:1)

使用Promise.all()等待创建的所有承诺,然后解决父承诺

像这样(未经测试)

//FIND CHECKED OUT FILES
getCheckedOutFiles = function () {
    console.log('Get checked out files');
    var d = $q.defer();

    // Store final results and pass to then callback
    var checkedOutFiles = window.x = [];

    // Promise, returns collection with all sites 
    SiteService.getAllSites()
        .then(sites => {
            // For each site get lists then get items matching filter
            sites.forEach(function (site) {
                var web = new $pnp.Web(site.url);

                return web.lists
                    .filter("BaseTemplate eq 101")
                    .get() // Returns promise with all lists matching filter 
                    .then(lists => {
                        let promises = []
                        // Go through each list and find matching item 
                        lists.forEach(function (list) {

                            let prom = web.lists.getByTitle(list.Title).items
                                .filter("CheckoutUser ne null")
                                .expand("File, File/Author, File/ModifiedBy, File/CheckedOutByUser")
                                .get() // Returns promise with all items matching filter 
                                .then(files => {
                                    // Loop through each item, get properties, add to collection 
                                    files.forEach(function (f) {
                                        var fileObject = {
                                            fileName: f.File.Name,
                                            fileUrl: f.File.ServerRelativeUrl,
                                            absoluteUrl: f.File.ServerRelativeUrl,
                                            checkedTo: f.File.CheckedOutByUser.Title,
                                            modified: f.Modified,
                                            modifiedBy: f.File.ModifiedBy.Title,
                                            createdBy: f.File.Author.Title,
                                            created: f.Created,
                                            version: f.File.UIVersionLabel
                                        };
                                        // Add file to collection 
                                        checkedOutFiles.push(fileObject);
                                    }, this);
                                })
                                .catch(e => {
                                    console.log(e);
                                });
                            promises.push(prom)
                        });
                        // "Ideally" - When all files retrieved return collection of results 
                        Promise.all(promises).then(function(){
                            d.resolve(checkedOutFiles);
                        })
                        return null;
                    })
                    .catch(e => {
                        console.log(e);
                    });
            }, this);
            return null;
        });
    return d.promise;
};

// Returns promise with all checkedout file 
getCheckedOutFiles().then(files => {
    console.log("RESULTS", files);
    d.resolve(files);
});

答案 1 :(得分:1)

这些是需要修复的事情:

  1. 您有两个单独的循环,您有承诺管理。你需要在数组中收集这些promise,然后在它们上使用Promise.all()来知道循环中的所有promise都已完成。

  2. 您通过创建d承诺使用反模式,然后手动解析它。相反,您应该返回SiteService.getAllSites().then()承诺,然后在其中,返回承诺链,以便所有内容都链接(包括正确的错误处理)。

  3. 刚刚登录的.catch()处理程序正在“吃”错误。如果您.catch()并且不重新抛出,它会将该承诺变为已解决的承诺,从而“吃掉”错误而不是传播它。

  4. 以下是解决这些问题的方法:

    //FIND CHECKED OUT FILES
    function getCheckedOutFiles() {
        console.log('Get checked out files');
    
        // Store final results and pass to then callback
        var checkedOutFiles = window.x = [];
    
        // Promise, returns collection with all sites 
        return SiteService.getAllSites().then(sites => {
                // For each site get lists then get items matching filter
                var promises = [];
                sites.forEach(function (site) {
                    var web = new $pnp.Web(site.url);
    
                    promises.push(web.lists
                        .filter("BaseTemplate eq 101")
                        .get() // Returns promise with all lists matching filter 
                        .then(lists => {
                            // Go through each list and find matching item 
                            var promises2 = [];
                            lists.forEach(function (list) {
                                promises2.push(web.lists.getByTitle(list.Title).items
                                    .filter("CheckoutUser ne null")
                                    .expand("File, File/Author, File/ModifiedBy, File/CheckedOutByUser")
                                    .get() // Returns promise with all items matching filter 
                                    .then(files => {
                                        // Loop through each item, get properties, add to collection 
                                        files.forEach(function (f) {
                                            var fileObject = {
                                                fileName: f.File.Name,
                                                fileUrl: f.File.ServerRelativeUrl,
                                                absoluteUrl: f.File.ServerRelativeUrl,
                                                checkedTo: f.File.CheckedOutByUser.Title,
                                                modified: f.Modified,
                                                modifiedBy: f.File.ModifiedBy.Title,
                                                createdBy: f.File.Author.Title,
                                                created: f.Created,
                                                version: f.File.UIVersionLabel
                                            };
                                            // Add file to collection 
                                            checkedOutFiles.push(fileObject);
                                        }, this);
                                    })
                                    .catch(e => {
                                        console.log(e);
                                        // propagate error
                                        throw e;
                                    }));
                            });
                            return Promise.all(promises2);
                        }).catch(e => {
                            console.log(e);
                            // propagate error
                            throw e;
                        }));
                }, this);
                return Promise.all(promises).then(() => {
                    // make checkedOutFiles by the final resolve value
                    return checkedOutFiles;
                });
            });
    };
    
    // Returns promise with all checkedout file 
    getCheckedOutFiles().then(files => {
        console.log("RESULTS", files);
    }).catch(err => {
        // handle error here
    });
    

    这可以通过在Bluebird promise库中使用Promise.map()来简化,它会迭代一个数组,调用一个promise产生函数并等待所有的promises完成(.each()Promise.all())。