A continuación se muestra un fragmento de mi función javascript. Toma una matriz de tamaño arbitrario de objetos travelDataGroups[{}] e itera sobre ella. Dentro de forEach() tengo que llamar a newUser() , que es asíncrono, y dentro de eso tengo que llamar a loadOtherUsersPayRate() que es asíncrono.
Después de que se resuelvan todas las devoluciones de llamada y se complete el bucle, necesito llamar a makeWorkbookDownloadObj() , el problema es que solo se puede llamar una vez, de lo contrario, corrompe el objeto.
myGroupWorkReportObj.travelDataGroups.forEach( travelerData => { // add the pay rate for this user const someUser = new User( travelerData.employeeId , function() { // add the pay rate for this user and project const projectId = travelerData.projectId; const payRate = loadOtherUsersPayRate( projectId, someUser ) .then( payRate => { //create a row of travel data const rowOfData = [ travelerData.firstName, travelerData.lastName, travelerData.travelHours, financial( payRate.pay / 2 ) ]; // push the row of data into the sheet thisSheet.data.push( rowOfData ); // need to only call this once, when all callbacks are resolved // makeWorkbookDownloadObj( workbookObj ); }); });EDITAR código de trabajo final:
const userPromises = []; // wrap the User class in a Promise var aUserPromise = ( travelerData ) => { return new Promise( ( resolve, reject ) => // new User( employeeId, ( someUser ) => { // return new Promise( ( resolve, reject ) => new User( travelerData.employeeId, ( someUserObj ) => { // add the pay rate for this user and project loadOtherUsersPayRate( travelerData.projectId, someUserObj ) .then( payRate => { //create a row of travel data const rowOfData = [ travelerData.firstName, travelerData.lastName, travelerData.travelHours, financial( payRate.pay / 2 ) ]; // push the row of data into the sheet thisSheet.data.push( rowOfData ); resolve(); } ); } ); } ); }; myGroupWorkReportObj.travelDataGroups.forEach(( travelerData ) => { // add the pay rate for this user ** this line would push the function, but not execute it (until later), ** so did in two lines as below // userPromises.push(aUserPromise(travelerData)); var myRun = aUserPromise( travelerData ); userPromises.push( myRun ); }); Promise.allSettled( userPromises ) .then( ()=> { makeWorkbookDownloadObj( workbookObj ) });Hago esto: uso Promise.all; consulte aquí para obtener documentos:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
Tenga en cuenta que el siguiente código no está probado, pero puede ver cómo hacerlo:
const promises = [] promises.push( loadOtherUsersPayRate( projectId, someUser ) .then( payRate => { //create a row of travel data const rowOfData = [ travelerData.firstName, travelerData.lastName, travelerData.travelHours, financial( payRate.pay / 2 ) ]; // push the row of data into the sheet thisSheet.data.push( rowOfData ); // need to only call this once, when all callbacks are resolved // makeWorkbookDownloadObj( workbookObj ); }); ) Promise.all(promises).then( ()= > makeWorkbookDownloadObj( workbookObj ));Siguiendo su comentario y usando Promise ALL y el mismo patrón usado por la respuesta anterior:
const userPromises = []; myGroupWorkReportObj.travelDataGroups.forEach( travelerData => { // add the pay rate for this user userPromises.push(new User( travelerData.employeeId , function() { // add the pay rate for this user and project const projectId = travelerData.projectId; const payRate = loadOtherUsersPayRate( projectId, someUser ) .then( payRate => { //create a row of travel data const rowOfData = [ travelerData.firstName, travelerData.lastName, travelerData.travelHours, financial( payRate.pay / 2 ) ]; // push the row of data into the sheet thisSheet.data.push( rowOfData ); }) })); }); Promise.all(userPromises).then(() => { makeWorkbookDownloadObj( workbookObj ); });Las verdaderas promesas que hay que resolver son las de creación de usuarios.