Как дождаться выполнения обещания перед началом следующей итерации «бесконечного» для l oop in JavaScript - PullRequest
0 голосов
/ 07 августа 2020

Я пытаюсь понять, как дождаться выполнения обещания перед началом следующей итерации в for l oop. Кто-то предложил мне использовать функцию setInterval () вместо a для l oop, что нормально, если вы можете угадать время, которое потребуется для выполнения обещания, но это, очевидно, не идеально.

const puppeteer = require('puppeteer-extra')
const StealPlugin = require('puppeteer-extra-plugin-stealth')

puppeteer.use(StealPlugin())
let arrayOfUrls = [
    "https://google.com",
    "https://facebook.com",
    "https://youtube.com",
];

let initialIndex = 0;
let finalIndex = 0;

async function scraper(url) {
    const browser = await puppeteer.launch({headless: false});
    const page = await browser.newPage();
    await page.goto(url);
    await page.screenshot({path: 'example' + initialIndex.toString() + '.png'});
    await console.log(url + "  screenshot complete!")
    await browser.close();
}

const interval = setInterval(() => {
    if (initialIndex < arrayOfUrls.length) {
        scraper(arrayOfUrls[initialIndex]);
        initialIndex += 1;
    } else {
        clearInterval(interval);
        console.log("All complete!")
        loopy()
    }
}, 300)

function loopy() {
    setInterval(() => {
        if (finalIndex === arrayOfUrls.length) {
            finalIndex = 0;
        }
        scraper(arrayOfUrls[finalIndex]);
        finalIndex += 1;
    }, 300)
}

Этот приведенный выше код на данный момент является просто экспериментальным, но в конечном итоге я пытаюсь выполнить серию запросов API с использованием URL-адресов из текстового файла, а затем создать массив, содержащий объект для каждого URL-адреса. Это const interval = setInterval(() => { в моем коде.

Тогда я хочу иметь возможность периодически проверять каждый запрос снова и проверять, есть ли изменение в запросе API, и чтобы это выполнялось на неопределенный срок. Это функция loopy() в моем экспериментальном коде. Если есть, я хочу отправить себе уведомление.

Моя текущая реализация работает нормально, если я установил время для setInterval() на что-то высокое, например 5000 мс, но если оно будет чем-то низким, например, 300 мс, тогда обещания не может быть заполнен достаточно быстро, и я получаю эту ошибку:

(node:9652) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 exit listeners added to [process]. Use emitter.setMaxListeners() to increase limit

Как лучше всего реализовать logi c для такой программы?

Изменить:

После идеи в комментариях от WS C я попытался сделать следующее, и, похоже, это сработало.

const puppeteer = require('puppeteer-extra')
const StealPlugin = require('puppeteer-extra-plugin-stealth')

puppeteer.use(StealPlugin())
let arrayOfUrls = [
    "https://google.com",
    "https://facebook.com",
    "https://youtube.com",
];

let initialIndex = 0;
let finalIndex = 0;

async function scraper(url) {
    const browser = await puppeteer.launch({headless: false});
    const page = await browser.newPage();
    await page.waitFor(5000)
    await page.goto(url);
    await page.screenshot({path: 'example' + initialIndex.toString() + '.png'});
    await console.log(url + "  screenshot complete!")
    await browser.close();
}

async function initialScrape() {
    if (initialIndex < arrayOfUrls.length) {
        await scraper(arrayOfUrls[initialIndex]);
        initialIndex += 1;
        initialScrape()
    } else {
        console.log("All complete!")
        loopy()
    }
}


async function loopy() {
    if (finalIndex === arrayOfUrls.length) {
        finalIndex = 0;
    }
    await scraper(arrayOfUrls[finalIndex]);
    finalIndex += 1;
    loopy()
}

initialScrape()

Я реализовал искусственная задержка в функции scraper() вместо await page.waitFor(5000). Однако я не совсем уверен, рекомендуется ли эта конкретная реализация для программы, которую я пытаюсь достичь.

1 Ответ

1 голос
/ 07 августа 2020

Синтаксис async / await отлично работает с циклами. Вам не нужно использовать рекурсивный подход.

async function main() {
    for (let initialIndex=0; initialIndex<arrayOfUrls.length; initialIndex++) {
        await scraper(arrayOfUrls[initialIndex]);
    }
    console.log("All complete!");
    while (true) {
        for (let finalIndex=0; finalIndex<arrayOfUrls.length; finalIndex++) {
            await scraper(arrayOfUrls[finalIndex]);
        }
    }
}
main().catch(console.error);

Или еще проще с for … of циклами:

async function main() {
    for (const url of arrayOfUrls) {
        await scraper(url);
    }
    console.log("All complete!");
    while (true) {
        for (const url of arrayOfUrls) {
            await scraper(url);
        }
    }
}
main().catch(console.error);

Кстати, для повышения производительности я бы рекомендовал позвонить puppeteer.launch({headless: false}); только один раз, а затем сделайте все снимки экрана с одним и тем же экземпляром браузера.

...