Angular Promise异常:外层Then提前触发的排查与解决
Let's break down why your outer .then is firing early, and fix it:
The Root Cause
In your Update 1 code, you correctly created a promises array to track all your asynchronous SharePoint list queries, but you forgot to return that array from the IIFE passed to $q.all. Since $q.all receives undefined instead of a list of promises, it immediately resolves, triggering your DataTables rendering before all queries finish.
The Fixed Code
Here's the corrected version with the critical missing line added:
function GetData(billCycleId, clientCode, jobCodes, engagementCode) { var deferred = $q.defer(); var enhanceFunctions = [ function(searchResultRow) { return spService.AddHyperLinkOnFields(searchResultRow, config.HyperLinks); }, function(searchResultRow) { return spService.AddPresenceOnFields(searchResultRow, config.UserFields); }, function(searchResultRow) { return spService.FormatDateFields(searchResultRow, config.DateFields, generalConfig.DateTimeFormat); }, function(searchResultRow) { return spService.AddImageMapping(searchResultRow, config.ImageFields); }, function(searchResultRow) { return spService.FormatNumberFields(searchResultRow, config.NumberFields); } ]; var selectProperties = spService.TransformFieldsToSelectProperties(config.Fields); var extendedSelectProperties = selectProperties.slice(); // copy array var hyperLinkedProperties = spService.TransformFieldsToSelectProperties(config.HyperLinks) extendedSelectProperties = extendedSelectProperties.concat(hyperLinkedProperties); var result =[]; spService.GetAllListsFromWeb() .then(function (lists) { var listEnumerator = lists.getEnumerator(); return $q.all( (function(){ var promises = []; while (listEnumerator.moveNext()) { var oList = listEnumerator.get_current(); var title = oList.get_title(); var id = oList.get_id(); if (title.indexOf('Bill Cycles') !== -1) { promises.push( GetRelatedBillCyclesFromList( id, extendedSelectProperties, billCycleId, clientCode, jobCodes, engagementCode, enhanceFunctions ) .then(function (data) { var trimmedData = spService .SpSearchQuery .TrimSearchResultsToSelectProperties( data, selectProperties ); trimmedData.forEach(function(item){ result.push(item); }); }) ); } } // Critical: Return the array of promises so $q.all can wait for all of them return promises; })() ); }) .then(function(data){ var dataTable = $(tableSelector).DataTable(); dataTable.clear().rows.add(result).columns.adjust().draw(); vm.ValidDataLoaded = true; }); }
Key Fixes Explained
- Return the
promisesarray: This tells$q.allto wait until every asynchronous query in the array has completed before resolving the promise chain. Without this,$q.allhas nothing to wait for and moves to the next.thenimmediately. - Your existing logic for collecting results into the
resultvariable works fine once$q.allproperly waits for all queries to finish.
Optional Optimization (Cleaner Result Collection)
If you want to avoid relying on an external result variable, you can use the resolved values from $q.all directly to build your dataset:
.then(function (lists) { var listEnumerator = lists.getEnumerator(); var promises = []; while (listEnumerator.moveNext()) { var oList = listEnumerator.get_current(); var title = oList.get_title(); var id = oList.get_id(); if (title.indexOf('Bill Cycles') !== -1) { promises.push( GetRelatedBillCyclesFromList( id, extendedSelectProperties, billCycleId, clientCode, jobCodes, engagementCode, enhanceFunctions ) .then(function (data) { // Return trimmed data directly instead of pushing to external array return spService.SpSearchQuery.TrimSearchResultsToSelectProperties(data, selectProperties); }) ); } } // Wait for all promises, then flatten the array of results return $q.all(promises).then(function(allTrimmedData) { return allTrimmedData.flat(); // Combine all arrays into one }); }) .then(function(result){ var dataTable = $(tableSelector).DataTable(); dataTable.clear().rows.add(result).columns.adjust().draw(); vm.ValidDataLoaded = true; });
This makes the code more predictable by eliminating side effects on external variables.
内容的提问来源于stack exchange,提问作者Luis Valencia

