Асинхронный запрос для веб-сканера - PullRequest
0 голосов
/ 12 февраля 2019

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

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

Я много гуглял и пробовал разные вещи, такие как использование пользовательской функции async-forEach или request-обещания вместо запроса, но ничего не получалось.

const request = require('request');
const rp = require('request-promise');
const cheerio = require('cheerio');
const fs = require('fs');

let verbs = [];
let conjugations = [];
fs.readFileSync('verbs.txt', 'utf-8').split(/\r?\n/).forEach
(function(line){
  verbs.push(line);
});

verbs.forEach((verb) => {
    const URI = encodeURI("https://ru.wiktionary.org/wiki/" + verb);


    var options = {
        uri: URI,
        transform: function (body) {
            return cheerio.load(body);
        }


    };

    rp(options).then(function ($) {
        let table = $('span#Русский.mw-headline').parent().nextAll('table').first();
        conjugations.push(table.text());
        console.log(conjugations[0]);

    })
    .catch(function (err) {
    });


})




        
  
    

1 Ответ

0 голосов
/ 12 февраля 2019

Используйте Promise.all , если порядок важен.

Метод Promise.all () возвращает одно Обещание, которое разрешается, когда все обещания передаются как повторяемые.разрешены или когда итерируемый не содержит обещаний.Он отклоняет причину первого отклонения обещания.

Пример поддержания порядка:

const verbs = ["hello", "world", "example"];

let timeout = 2000;
const promises = verbs.map(verb=>{
  timeout -= 500;
  return new Promise((resolve,reject)=>{
    setTimeout(function(){
      resolve(verb);
    }, timeout);
  });
});

Promise.all(promises).then(dataArray=>console.log(dataArray));

Решение с вашим кодом.

const promises = verbs.map((verb) => {
  const URI = encodeURI("https://ru.wiktionary.org/wiki/" + verb);
  var options = {
    uri: URI,
    transform: function(body) {
      return cheerio.load(body);
    }


  };

  return rp(options);
})

Promise.all(promises).then(dataArray=>{
     dataArray.forEach(function($) {
      let table = $('span#Русский.mw-headline').parent().nextAll('table').first();
      conjugations.push(table.text());
      console.log(conjugations[0]);
    })
}).catch(function(err) {});

Недостаток: если один запрос не сработает, все они не пройдут.

В качестве альтернативы, вы можете сделатькак-то так, используя индекс каждого глагола (используя Promise.all, чтобы определить, когда все сделано, но этот шаг можно игнорировать ...)

const verbs = ["hello", "world", "example"];

const conjugations = [];
let timeout = 2000;
const promises = verbs.map((verb, index)=>{
  return new Promise((resolve, reject)=>{
    setTimeout(function(){
      conjugations[index] = verb;
      resolve();
    }, timeout);
    timeout -= 500;
  });
});

Promise.all(promises).then(()=>console.log(conjugations));

Пример с вашим кодом.

const request = require('request');
const rp = require('request-promise');
const cheerio = require('cheerio');
const fs = require('fs');

let verbs = [];
let conjugations = [];
fs.readFileSync('verbs.txt', 'utf-8').split(/\r?\n/).forEach(function(line) {
  verbs.push(line);
});

verbs.forEach((verb, index) => {
      const URI = encodeURI("https://ru.wiktionary.org/wiki/" + verb);


      var options = {
        uri: URI,
        transform: function(body) {
          return cheerio.load(body);
        }
      };

      rp(options).then(function($) {
          let table = $('span#Русский.mw-headline').parent().nextAll('table').first();
          conjugations[index] = table.text();
          console.log(conjugations[index]);

        })
        .catch(function(err) {});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...