mister.cake
mister.cake

Reputation: 165

async/await promise logic issues

I am in the process of learning how to use async/await with promises. I am having a few issues with the first promise. Specifically:

var pres = mvc.Components.get("search1");
pres.data('results', {
  count: 0,
  output_mode: 'json_rows'
}).on("data", function(results) {
  alldata3 = results._data;
  console.log(alldata3)
});    

I am pulling results from a function within another script. The result for 'search1' is very large. It takes longer then search two for instance. The issue I am having is that it does not wait until 'results._data' has fully been assigned to alldata3 to move on to itVolTwo(). This ends up giving me an async error indicating 'alldata3.rows' is undefined. Is there anyway to rework this so it waits until it receives the full results from search1? Whats the best course of action here? Thanks for any help!

var alldata3 = new Object();
var alldata32 = new Object();
// Promise
const itVolOne = new Promise(
  (resolve, reject) => {
    if (boolpool) {
      var pres = mvc.Components.get("search1");
      pres.data('results', {
        count: 0,
        output_mode: 'json_rows'
      }).on("data", function(results) {
        alldata3 = results._data;
        console.log(alldata3)
      });
      console.log(alldata3)
      var rdbms1 = mvc.Components.get("search2");
      rdbms1.data('results', {
        count: 0,
        output_mode: 'json_rows'
      }).on("data", function(results) {
        alldata32 = results._data;
        console.log(alldata32)
      });
      console.log(alldata32)

      console.log(alldata3, alldata32)
      resolve(alldata3, alldata32)
    } else {
      const reason = new Error('Unable to get the datas');
      reject(reason);
    }
  }
);

var rdbmsData = new Object();
async function itVolTwo() {
  return new Promise(
    (resolve, reject) => {
      for await (let row of alldata3.rows) {
        rdbmsData[row[0]] = {
          "crit": row[1],
          "high": row[2],
          "med": row[3],
          "low": row[4]
        }
      }
      console.log(rdbmsData)
      resolve(rdbmsData);
    }
  );
};

// 2nd promise
var presData = new Object();
async function itVolThree() {
  return new Promise(
    (resolve, reject) => {
      for await (let row of alldata32.rows) {
        presData[row[0]] = {
          "crit": row[1],
          "high": row[2],
          "med": row[3],
          "low": row[4]
        }
      }
      console.log(presData)
      resolve(presData);
    }
  );
};
// 3rd promise
var endData = new Object();
async function itVolFour() {
  return new Promise(
    (resolve, reject) => {
      function sum(a, b) {
        Object.keys(b).forEach(k => {
          if (b[k] && typeof b[k] === 'object') return sum(a[k] = a[k] || {}, b[k]);
          a[k] = (+a[k] || 0) + +b[k];
        });
        return a;
      }
      endData = [rdbmsData, presData].reduce(sum);
      console.log(endData)
      resolve(endData);
    }
  );
};
// call our promise
async function itInit() {
  try {
    console.log('I got to the call YEY!');

    let stepOne = await itVolOne;
    let stepTwo = await itVolTwo();
    let stepThree = await itVolThree();
    let stepFour = await itVolFour();

    console.log(endData);
    console.log('Done');
  } catch (error) {
    console.log('u done f'
      ed up ');
    }
  }

  (async() => {
    await itInit();
  })();

Upvotes: 1

Views: 154

Answers (1)

Mauro Stepanoski
Mauro Stepanoski

Reputation: 725

You should 'promisify' the event emitter objects (something.data.on), and then you can await the results:

  const itVolOne = async () => {
    if (boolpool) {
        const pres = mvc.Components.get("search1");
        const alldata3 = await new Promise(resolve => {
             pres.data('results', {count: 0, output_mode: 'json_rows'}).on("data",
               results => {
                   resolve(results._data);
               }
             );
        });
        console.log(JSON.stringify(alldata3));

        const rdbms1 = mvc.Components.get("search2");
        const alldata32 = await new Promise(resolve => {
           rdbms1.data('results', {count: 0, output_mode: 'json_rows'}).on("data",
             results => {
                resolve(results._data);
             }
           );
        });

        console.log(JSON.stringify(alldata32));

        return { alldata3, alldata32 }
    } else {
       throw new Error('Unable to get the datas');
    }
  }

So, now the itVolOne function returns all the results in a "synchronized way" and the remaining functions can be rewritten:

  const itVolTwo =  alldata3 => {
      return alldata3.rows.reduce((rdbmsData, row) => {
          rdbmsData[row[0]] = {
            "crit": row[1],
            "high": row[2],
            "med":  row[3], 
            "low":  row[4]
          };

          return rdbmsData;
      }, {});
  }

  const itVolThree = alldata32 => {
     return alldata32.rows.reduce((presData, row) => {
          presData[row[0]] = {
             "crit": row[1],
             "high": row[2],
             "med":  row[3], 
             "low":  row[4]
          };
          return presData;
     }, {});
  }

  const itVolFour = (rdbmsData, presData) => {
     function sum(a, b) {
        Object.keys(b).forEach(k => {
            if (b[k] && typeof b[k] === 'object') return sum(a[k] = a[k] || {}, b[k]);
            a[k] = (+a[k] || 0) + +b[k];
        });
        return a;
      }
      return [rdbmsData, presData].reduce(sum);
  }

Now you can await only in the first step:

  async function itInit() {
    try {
        console.log('I got to the call YEY!');

        const { alldata3, alldata32 } = await itVolOne();
        const stepTwo = itVolTwo(alldata3);
        const stepThree = itVolThree(alldata32);
        const endData = itVolFour(stepTwo, stepThree);

        console.log(JSON.stringify(endData));
        console.log('Done');
    }
    catch (error) {
        console.log('u done f\'ed up');
    }
  }

And call the main function:

itInit();

That's all.

Upvotes: 1

Related Questions