Как выполнить цикл через асинхронную функцию в Nodejs

Вот пример кода, который я использую для интеграции selenium WebDriver JS ax для проверки доступности моего веб-сайта:

var AxeBuilder = require('axe-webdriverjs');
var WebDriver = require('selenium-webdriver');

var driver = new WebDriver.Builder()
  .forBrowser('firefox')
  .build();

driver
  .get('https://dequeuniversity.com/demo/mars/')
  .then(function() {
    AxeBuilder(driver).analyze(function(err, results) {
      if (err) {
        // Handle error somehow
      }
      console.info(results);
    });
  });

Здесь анализируется один URL. Может ли кто-нибудь помочь мне разобрать несколько URL-адресов? Я бы хотел, чтобы результаты всех URL-адресов были напечатаны в качестве входных данных для driver.get (). Любая помощь будет оценена по достоинству!

Ссылка - https://github.com/dequelabs/axe-webdriverjs

await каждый Promise или использовать Promise.all?
CertainPerformance 18.12.2018 02:15
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
1
386
3

Ответы 3

Поэтому я отформатирую комментарий @ CertainPerformance как ответ.

Самый простой подход - использовать современный синтаксис async/await:

for (const url of [url1, url2, url3]) {
    await driver
      .get(url)
      .then(async function() {
        await AxeBuilder(driver).analyze(function(err, results) {
          if (err) {
            // Handle error somehow
          }
          console.info(results);
        });
      });
}

Не забудьте заменить url1, url2, url3 своими URL-адресами.

P.S. как указано в @ jfriend00 (в комментариях ниже), мы не знаем, действительно ли функция AxeBuilder возвращает обещание или нет. Так что в последнем случае await до него (и async) может оказаться ненужным.

Это не будет ждать завершения AxeBuilder().analyze() перед переходом к следующей итерации цикла.

jfriend00 18.12.2018 04:49

@ jfriend00 Пропустил, исправлено!

Nurbol Alpysbayev 18.12.2018 04:53

Я не знаю эту библиотеку, но маловероятно, что .analyze () вернет обещание и получит обратный вызов. Если он не вернет обещание, await не сделает ничего полезного.

jfriend00 18.12.2018 05:45

@ jfriend00 Ага, постскриптум добавил.

Nurbol Alpysbayev 18.12.2018 05:56

Вы по-прежнему не показываете решение, которое фактически ожидало бы выполнения всех асинхронных операций перед повторением цикла.

jfriend00 18.12.2018 06:28

@ jfriend00 Я что-то упускаю. Что это за штуки?

Nurbol Alpysbayev 18.12.2018 06:33

Я уже говорил об этом в своем первом комментарии здесь. Подсказка, нужно "промисифицировать" .analyze().

jfriend00 18.12.2018 06:42

указанное выше решение будет работать, но оно будет сериализовано, то есть вы получите результат обещания driver.get, а затем analyze результат одного URL-адреса перед переходом к следующему. возможно, вы могли бы использовать promise.all, чтобы делать все это параллельно. Что-то вроде

function executeGetPromises() {
    var getPromises = [];
    var drivers = [];
    for (const url of [url1, url2, url3]) {
        var driver = new WebDriver.Builder().forBrowser('firefox').build();
        getPromises.push(driver.get(url));
        drivers.push(driver);
    }

    var analysePromises = [];
    int index = 0;
    Promise.all(getPromises.map(p => p.catch(e => e)))
        .then(results => {
            for (int i=0; i< results.length; i++) {
                var result = results[i];
                if (!(result instanceof Error)) {
                    analysePromises.push(AxeBuilder(drivers[i]).analyze);
                }
            }
        executeAnalysePromises(analysePromises);
    });
}

function executeAnalysePromises (analysePromises) {
    Promise.all(analysePromises.map(p => p.catch(e => e)))
    .then(results => {
        results.forEach(result => {
            if (!(result instanceof Error)) {
                console.info(result);
            }
        });
    });
}

здесь мы отслеживаем все drivers, и все обещания driver.get выполняются параллельно, и как только все getPromises возвращаются (либо разрешены / отклонены), analysePromises запускается параллельно.

Обновлено: более простой подход с использованием асинхронных функций. Вышеупомянутое немного сложно, вы можете добиться того же, используя асинхронные функции.

async function executeTask (driver, url) {
    try{
        await driver.get(url);
        let result = await AxeBuilder(driver).analyze();
        return Promise.resolve(result);
    } 
    catch(err) {
        return Promise.reject(err);
    }
}

function iterateThroughUrls(urls) {
    urls.forEach(url => {
        var driver = new WebDriver.Builder().forBrowser('firefox').build();
        executeTask(driver, url).then(result => {
            console.info(result);
        }).catch(err => {
            //handle errors
        });
    });
}

Привет, Мринал, во-первых, спасибо! Быстрый вопрос: что, если я не хочу, чтобы это работало параллельно и сериализовало этот точный код? Он работает безупречно, единственная проблема в том, что если я даю ему большое количество URL-адресов, он дает сбой. Пожалуйста, помогите!

sulaxe 23.12.2018 00:04

Используйте Promise.all и сопоставьте массив URL-адресов.

const urlArray = [url1,url2,url3,...];
const finalResult = await Promise.all(urlArray.map(async url=>{
   return await driver.get(url);
}))

вы получите весь результат в массиве finalResult.

Другие вопросы по теме