Estoy tratando de pasar un resultado (matriz) de una promesa a una función que itera sobre este resultado, haciendo una solicitud de obtención para cada elemento y creando un nuevo objeto con los resultados antes de devolverlo. El problema es que el objeto se devuelve antes de que se resuelvan las promesas y lo llenen. ¿Cuál es la forma correcta de devolver un objeto poblado de varias promesas?
function getPackageDetails(packages) { var detailedPackages = {}; angular.forEach(packages, function(p) { vsmsPackageFactory.getPackage(p.id) .then(function(response) { var subsystem = response.data.packageManifest.subsystem; var partNumber = response.data.packageManifest.resultConfig.partNumber; var packageName = response.data.packageMetaData.packageName; if(detailedPackages[subsystem] === undefined) { detailedPackages[subsystem] = {}; } if(detailedPackages[subsystem][partNumber] === undefined) { detailedPackages[subsystem][partNumber] = {}; } detailedPackages[subsystem][partNumber][packageName] = response.data; }); }); return detailedPackages; // returns before all promises resolved } vsmsCampaignFactory.getCampaignPackages(queryString) .then(function(response) { vm.packageList = getPackageDetails(response.results); });Debería considerar usar $q.all para aquellos casos en los que puede reunir todas las promesas en una sola matriz de promesas y luego pasarlas a $q.all y devolver la promesa resultante. Se asegurará de que está devolviendo data después de que se hayan realizado todas las promesas.
En su código, solo está ejecutando sus llamadas ajax asíncronas sin preocuparse de si se completaron o no. Y justo después de eso, está devolviendo datos detailedPackages de paquetes. Pero obviamente va a estar vacío.
Código
function getPackageDetails(packages) { var detailedPackages = {}; var promises = []; //promise array angular.forEach(packages, function(p) { var promise = vsmsPackageFactory.getPackage(p.id) .then(function(response) { var subsystem = response.data.packageManifest.subsystem; var partNumber = response.data.packageManifest.resultConfig.partNumber; var packageName = response.data.packageMetaData.packageName; if(detailedPackages[subsystem] === undefined) { detailedPackages[subsystem] = {}; } if(detailedPackages[subsystem][partNumber] === undefined) { detailedPackages[subsystem][partNumber] = {}; } detailedPackages[subsystem][partNumber][packageName] = response.data; }); promises.push(promise); }); return $q.all(promises).then(function(){ return detailedPackages; // returned data after all promises are done }); }esto podría lograrse usando prometer todo, aquí .
var promises = []; promises.push(new Promise(function (resolve, reject) { vsmsPackageFactory.getPackage(p.id) .then(function(response) { ... resolve('If you want to return something') }); }); //After the loop it's finished you execute your promises Promise.all(promises).then(function (values) { ... perform more code });