JS async / await не ждет, пока мои функции выполнят свое обещание - PullRequest
0 голосов
/ 16 ноября 2018

Можете ли вы помочь мне понять, почему это не работает:

Я работаю в Аурелии и пытаюсь проверить некоторые входные данные с помощью контроллера проверки, который задокументирован здесь: https://aurelia.io/docs/plugins/validation#validation-controller

Теперь у меня есть карта этих данных, где мне нужно оценить каждую запись, и я хочу создать массив, где каждый элемент содержит результат проверки каждой записи, а когда все будет сделано, вернуть массив.

Так что-то вроде этого (упрощенно):

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;
      });
}

Теперь, конечно, это не сработает, потому что мне нужно подождать, пока контроллер проверки не выполнит свое обещание, прежде чем я смогу получить какие-либо данные обратно, и до сих пор у меня ничего не получалось.

Я прочитал, что если вы используете ключевое слово async / await, оно приостановит функцию, пока обещание не будет выполнено, поэтому я внес изменения, что-то вроде этого:

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

      InputDataMap.forEach(async(item) => {

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

Так вот, это тоже не работает, и это то, что меня интересует. Я полагаю, что моя функция «validateEntry» считается завершенной «await» после ее запуска и не ожидает разрешения обещания функции «validate ()» внутри «validateEntry». Могу ли я написать это так же просто, как это, с несколькими изменениями и все же заставить его работать?

Ответы [ 3 ]

0 голосов
/ 16 ноября 2018

Вы должны вернуть Promise от вашего validateEntry:

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

A then, просто возвращая его параметр, не требуется и ничего не делает, поэтому .then(result => { return result; }) можно удалить.

Обратный вызов async для forEach не заставит ValidateAll ждать проверки.Вам нужно подождать, пока все Обещания будут выполнены, и вернуть Обещание с ValidateAll, forEach можно заменить на map, чтобы вам не приходилось делать push вручную:

let validationResults = new Array();

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

Вам не нужен async здесь, потому что вам не нужен await здесь.Теперь validationResults содержит список Обещаний.Теперь вам нужно использовать Promise.all, чтобы дождаться их разрешения.

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

  return Promise.all(validationResults);
}

Теперь ValidateAll вернет Promise, который разрешится с массивом, содержащим результаты проверки.

Вы можете сократить код еще больше до:

function ValidateAll(InputDataMap){
  return Promise.all( InputDataMap.map(validateEntry) );
}
0 голосов
/ 16 ноября 2018

Вы должны вернуть Promise, содержащий все асинхронные операции, что-то вроде этого:

function ValidateAll(InputDataMap) {
  return Promise.all(InputDataMap.map(item => validateEntry(item)));
}
0 голосов
/ 16 ноября 2018

Я прочитал, что если вы используете ключевое слово async / await, оно приостановит функцию, пока обещание не будет выполнено, поэтому я внес изменения, что-то вроде этого:

Действительно, это такприостановить функцию, но async(item) => {//Code} - это другая функция, на которую не влияет внешняя функция

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

Также обратите внимание на ключевое слово async перед объявлением функции, которое означает, что вы должны использовать его через let results = await ValidateAll(inputData) иликак ValidateAll(inputData).then(results => {//Code})

function ValidateAll(InputDataMap){
      return Promise.all(InputDataMap.map(item => validateEntry(item)))
});
...