skip to Main Content

How to correctly resolve a Promise.all(…), I’m trying that after resolving the promise which generates a set of asynchronous requests (which are simple database queries in supabase-pg SQL) I’m iterating the result in a forEach , to make a new request with each of the results of the iterations.

But, try to save the result that it brings me in a new array, which prints fine in the console, but in the response that doesn’t work. It comes empty, I understand that it is sending me the response before the promise is finished resolving, but I don’t understand why.

In an answer to a previous question I was told to use await before the then, but I didn’t quite understand how to do it.

What am I doing wrong?

export const getReportMonthly = async(req: Request & any, res: Response, next: NextFunction) => {
    try {

      let usersxData: UsersxModalidadxRolxJob[] = [];
      let data_monthly: HoursActivityWeeklySummary[] = [];
      let attendance_schedule: AttendanceSchedule[] = [];
      let time_off_request: TimeOffRequestRpc[] = [];
      let configs: IndicatorConfigs[] = [];

      const supabaseService = new SupabaseService();

      const promises = [
        supabaseService.getSummaryWeekRpcWihoutFreelancers(req.query.fecha_inicio, req.query.fecha_final).then(dataFromDB => {
          data_monthly = dataFromDB as any;
        }),
        supabaseService.getUsersEntity(res).then(dataFromDB => {
          usersxData = dataFromDB as any;
        }),
        supabaseService.getAttendaceScheduleRpc(req.query.fecha_inicio, req.query.fecha_final).then(dataFromDB => {
          attendance_schedule = dataFromDB as any;
        }),
        supabaseService.getTimeOffRequestRpc(req.query.fecha_inicio, req.query.fecha_final).then(dataFromDB => {
          time_off_request = dataFromDB as any;
        }),
        supabaseService.getConfigs(res).then(dataFromDB => {
          configs = dataFromDB;
        }),

      ];

      let attendanceInMonthly = new Array();
      await Promise.all(promises).then(() => {
        attendance_schedule.forEach(element => {
          let start_date = element.date_start.toString();
          let end_date = element.date_end.toString();

          supabaseService.getTrackedByDateAndIDArray(start_date, end_date).then(item => {
            console.log(item);
            attendanceInMonthly.push(item);
          });
        });
      })

      res.json(attendanceInMonthly)

    } catch (error) {
      console.log(error);
      res.status(500).json({
        title: 'API-CIT Error',
        message: 'Internal server error'
      });
    }

2

Answers


  1. If you await a promise you could write the return of this in a variable and work with this normaly.
    So instead of your current code you could use the following changed code:

    export const getReportMonthly = async(req: Request & any, res: Response, next: NextFunction) => {
        try {
    
          let usersxData: UsersxModalidadxRolxJob[] = [];
          let data_monthly: HoursActivityWeeklySummary[] = [];
          let attendance_schedule: AttendanceSchedule[] = [];
          let time_off_request: TimeOffRequestRpc[] = [];
          let configs: IndicatorConfigs[] = [];
    
          const supabaseService = new SupabaseService();
    
          const promises = [
            supabaseService.getSummaryWeekRpcWihoutFreelancers(req.query.fecha_inicio, req.query.fecha_final).then(dataFromDB => {
              data_monthly = dataFromDB as any;
            }),
            supabaseService.getUsersEntity(res).then(dataFromDB => {
              usersxData = dataFromDB as any;
            }),
            supabaseService.getAttendaceScheduleRpc(req.query.fecha_inicio, req.query.fecha_final).then(dataFromDB => {
              attendance_schedule = dataFromDB as any;
            }),
            supabaseService.getTimeOffRequestRpc(req.query.fecha_inicio, req.query.fecha_final).then(dataFromDB => {
              time_off_request = dataFromDB as any;
            }),
            supabaseService.getConfigs(res).then(dataFromDB => {
              configs = dataFromDB;
            }),
    
          ];
    
          const resolvedPromises = await Promise.all(promises)
          const attendanceInMonthly = await Promise.all(
              resolvedPromises.map(
                  async (element) => {
                      let start_date = element.date_start.toString();
                      let end_date = element.date_end.toString();
                      return supabaseService.getTrackedByDateAndIDArray(start_date, end_date)
                  }
              )
          )
    
          console.log(attendanceInMonthly) // this should be your finaly resolved promise
    
          res.json(attendanceInMonthly)
    
        } catch (error) {
          console.log(error);
          res.status(500).json({
            title: 'API-CIT Error',
            message: 'Internal server error'
          });
        }
    

    Something like this should your code looks like. I am not sure if this solves exactly your code because your code has some syntax errors wich you have to solve for you.

    Login or Signup to reply.
  2. If I understand correctly, you launch a few requests, among which one (getAttendaceScheduleRpc, which assigns attendance_schedule) is used to launch some extra requests again, and you need to wait for all of these (including the extra requests) before returning?

    In that case, the immediate issue is that you perform your extra requests in "subqueries", but you do not wait for them.

    A very simple solution would be to properly separate those 2 steps, somehow like in DerHerrGammler’s answer, but using attendance_schedule instead of resolvedPromises as input for the 2nd step:

    let attendanceInMonthly = new Array();
    await Promise.all(promises);
    
    await Promise.all(attendance_schedule.map(async (element) => {
      let start_date = element.date_start.toString();
      let end_date = element.date_end.toString();
    
      const item = await supabaseService.getTrackedByDateAndIDArray(start_date, end_date);
    
      console.log(item);
      attendanceInMonthly.push(item);
    });
    
    res.json(attendanceInMonthly);
    

    If you are really looking to fine tune your performance, you could take advantage of the fact that your extra requests depend only on the result of one of your initial requests (getAttendaceScheduleRpc), so you could launch them as soon as the latter is fullfilled, instead of waiting for all the promises of the 1st step:

    let attendance_schedule: AttendanceSchedule[] = [];
    let attendanceInMonthly = new Array();
    
    const promises = [
      supabaseService.getAttendaceScheduleRpc(req.query.fecha_inicio, req.query.fecha_final).then(dataFromDB => {
        attendance_schedule = dataFromDB as any;
    
        // Immediately launch your extra (2nd step) requests, without waiting for other 1st step requests
        // Make sure to return when all new extra requests are done, or a Promise
        // that fullfills when so.
        return Promise.all(attendance_schedule.map(async (element) => {
          let start_date = element.date_start.toString();
          let end_date = element.date_end.toString();
    
          const item = await supabaseService.getTrackedByDateAndIDArray(start_date, end_date);
    
          console.log(item);
          attendanceInMonthly.push(item);
        });
      }),
      // etc. for the rest of 1st step requests
    ];
    
    await Promise.all(promises);
    
    res.json(attendanceInMonthly);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search