2017-09-05 68 views
1

我無法控制我的方法的使用承諾的流程:嵌套承諾控制流量在循環

//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將包含預期數據。

回答

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); 
}); 
+0

還有比你顯示需要解決這個問題。 'site.forEach()'中的return()。web.lists.filter()。get()。then()'並不等待這個承諾。 – jfriend00

+0

另外,這是一個承諾[反模式](https://github.com/petkaantonov/bluebird/wiki/Promise-anti-patterns)與OP的'd.resolve()',其中不需要包裝所有這一切在另一個承諾。 – jfriend00

1

這些都是需要固定的東西:

  1. 你有兩個單獨的循環,你有承諾管理。您需要在數組中收集這些承諾,然後使用Promise.all()來知道何時完成了循環中的所有承諾。

  2. 您正在使用反模式,方法是創建d承諾,然後手動解析它。相反,你應該返回SiteService.getAllSites().then()承諾,然後在那裏,返回承諾連鎖,所以一切都鏈接(包括適當的錯誤處理)。

  3. 您的.catch()處理程序,只是日誌是「吃」的錯誤。如果你是.catch()並且不重新拋出,它就會將這個承諾變成一個已經解決的承諾,從而「吃掉」錯誤並且不傳播它。

這裏是你如何解決這些:

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

這可以通過在青鳥承諾庫,將遍歷數組使用Promise.map(),調用一個承諾生產函數中,等待所有的略微簡化承諾完成(.each()Promise.all()的組合)。