Как уменьшить время выполнения нескольких асинхронных функций в Node JS? - PullRequest
0 голосов
/ 28 ноября 2018

Я хочу почистить некоторые веб-страницы и получить от них данные в Node js.Мой код работает, но для очистки и возврата всех данных требуется почти 1 минута.Я использовал асинхронные функции для каждого сайта и обещаю собрать всю информацию.Есть не более 100 сотен ссылок, над которыми я работал.Я думаю, что время работы слишком много для этого.Есть ли какие-либо проблемы в структуре моего кода (использование запроса-обещания, обещания, асинхронное ожидание и т. Д.), Которые вызывают задержку?Все функции могут работать параллельно / асинхронно, но мое ограничение заключается в том, что мне нужно подождать, пока все результаты не будут получены с каждого веб-сайта.Я ограничил время ожидания каждого запроса до 10 секунд.Если я уменьшу его намного больше, увеличатся существующие ошибки ETIMEDOUT, ECONNRESET, ESOCKETTIMEDOUT (от которых я до сих пор не могу избавиться).

Вот одна из моих функций очистки:

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

async function ntv() {
    var posts = [];
    try {
        const baseUrl = 'http://www.ntv.com';
        const mainHtml = await rp({uri: baseUrl, timeout: 10000});
        const $ = cheerio.load(mainHtml);
        const links =
            $(".swiper-slide")
                .children("a")
                .map((i, el) => {
                    return baseUrl + $(el).attr("href");
                }).get();

        posts = await Promise.map(links, async (link) => {
            try {
                const newsHtml = await rp({uri: link, timeout: 10000});
                const $ = cheerio.load(newsHtml);
                return {
                    title: $("meta[property='og:title']").attr("content"),
                    image: $("meta[property='og:image']").attr("content"),
                    summary: $("meta[property='og:description']").attr("content")
                }
            } catch (err) {
                if (err.message == 'Error: ETIMEDOUT') console.log('TIMEOUT error ' + link);
                else if (err.message == 'Error: read ECONNRESET') console.log('CONNECTION RESET error ' + link);
                else if (err.message == 'Error: ESOCKETTIMEDOUT') console.log('SOCKET TIMEOUT error ' + link);
                else console.log(err);
            }
        })
    } catch (e) {
        console.log(e)
    }
    return posts;
}

Моя основная функция, которая запускает все эти функции очистки:

var Promise = require("bluebird")
var fs = require("fs")

async function getData() {
    const sourceFunc = [func1(), func2(), ... , func10()];
    var news = [];

    await Promise.map(sourceFunc, async (getNews) => {
        try {
            const currentNews = await getNews;
            news = news.concat(currentNews);
        } catch (err) {
            console.log(err);
        }
    },{concurrency:10});

    news.sort(function(a,b){
        return new Date(b.time) - new Date(a.time);
    });
    fs.writeFile('./news.json', JSON.stringify(news, null, 3), (err) => {
        if (err) throw err;
    });
    return news;
}

1 Ответ

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

Я бы начал с добавления некоторых тестов в ваш скрипт.Выясните, какой шаг занимает больше всего времени в функции ntv(), и настройте его.

Мое другое предположение состоит в том, что анализ всего HTML с помощью cheerio является узким местом.Может быть более эффективно использовать String.prototype.substring() или RegExp() для извлечения ссылок и публикации информации.

ОБНОВЛЕНИЕ:

Проверьте, не является ли узкое место одновременные соединения TCP. Здесь - несколько советов о том, как его проверить / отрегулировать.

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

  1. Процесс # 1 генерирует список URL-адресов для извлечения
  2. Процесс # 2 берет URL-адрес из списка, получает HTML-код из него и сохраняет локально
  3. Процесс № 3 берет HTML-код и анализирует его

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

Если URL-адреса и HTML сохраняются в общей БД, вы можете распределять задачи между несколькими компьютерами, повышая производительность.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...