1

Can you help me understand why this doesn't work:

I'm working in Aurelia, and I try to validate some input data using the validation controller, which is documented here: https://aurelia.io/docs/plugins/validation#validation-controller

Now, I have a map of this data, where I need to evaluate each entry, and I want to create an array, where each item contains the validation result of each entry, and when everything is done, return the array.

So something like this (simplified):

function ValidateAll(InputDataMap){
  let validationResults = new Array();

  InputDataMap.forEach((item) => {
     validationResults.push(validateEntry(item));
  });

 return validationResults;
}

function validateEntry(item){

(aurelia's validation)controller.validate(item, "some value", "some rule")
      .then(result => {
        return result;
      });
}

Now, this will not work of course, because I need to wait for the validation controller to resolve it's promise before I can get any data back, and so far I've failed at that.

I read that if you use the async/await keyword it will pause a function until the promise has been resolved, so I made changes, something like this:

function ValidateAll(InputDataMap){
      let validationResults = new Array();

      InputDataMap.forEach(async(item) => {

         let result = await validateEntry(item);
         validationResults.push(result);
});

Now, this doesn't work either, and that's what I'm wondering about. I suppose that my "validateEntry" function is considered finished by the "await" once it's run, and doesn't wait for the "validate()" function's promise inside "validateEntry" to be resolved. Can I write it as simply as this with a few modifications and still get it to work?

robertpaulsen
  • 209
  • 4
  • 9
  • You could try using `Promise.all` to get all the results. – Roshan Nov 16 '18 at 11:51
  • Yes, I tried something like this, based on an example I saw: let validate = InputDataArray.map((value) => { return validateEntry(value); }); let validationResultObjects = Promise.all(validate); validationResultObjects.then(()=> { console.log="done"; }); But even after the Promise.all finished (running "then"), it had not resolved the promise within validateEntry. So I got no further,, – robertpaulsen Nov 16 '18 at 11:58

3 Answers3

2

You have to return a Promise from your validateEntry:

function validateEntry(item){
  return controller.validate(item, "some value", "some rule")
}

A then just returning its parameter is not required, and does nothing, so .then(result => { return result; }) can be removed.

The async callback for the forEach would not make ValidateAll to wait for the validation. You have to wait for all Promises to be resolved, and return a Promise from ValidateAll, the forEach can be replaced by map so that you don't need to do the push manually:

let validationResults = new Array();

validationResults = InputDataMap.map(item => validateEntry(item));

You don't need async here because you do not need an await here. Now validationResults contains a list of Promises. You now need to use Promise.all to wait until those are resolved.

function ValidateAll(InputDataMap){
  let validationResults = InputDataMap.map(item => validateEntry(item));

  return Promise.all(validationResults);
}

Now ValidateAll will return a Promise that will resolve with an array containing the results of the validation.

You could shorten the code even more to:

function ValidateAll(InputDataMap){
  return Promise.all( InputDataMap.map(validateEntry) );
}
t.niese
  • 39,256
  • 9
  • 74
  • 101
1

I read that if you use the async/await keyword it will pause a function until the promise has been resolved, so I made changes, something like this:

Indeed it does pause the function but async(item) => {//Code} is another function unaffected by the outer function

async function ValidateAll(InputDataMap){
      let validationResults = [];
      for (item of InputDataMap) {
          let result = await validateEntry(item);
          validationResults.push(result);
      }
      return validationResults;      
});

Also notice the async keyword in front of the function declaration, which mean you have to use it via let results = await ValidateAll(inputData) or like ValidateAll(inputData).then(results => {//Code})

function ValidateAll(InputDataMap){
      return Promise.all(InputDataMap.map(item => validateEntry(item)))
});
wiomoc
  • 1,069
  • 10
  • 17
  • 1
    A `return await` does not make much sense, it will wait for the resolve of the Promise just to pass the result to a new Promise that is implicitly created by `async`, so you could omit the `await` there. And without a `await` the `async` is not required anymore. – t.niese Nov 16 '18 at 12:09
1

You have to return a Promise containing all the async operations, something like this:

function ValidateAll(InputDataMap) {
  return Promise.all(InputDataMap.map(item => validateEntry(item)));
}
Denis Frezzato
  • 957
  • 6
  • 15