Очереди задач

Puppeteer представляет собой библиотеку для управления браузером Chromium через API на JavaScript, предоставляя полный контроль над браузерной средой. В контексте тестирования часто возникает необходимость последовательного выполнения действий с веб-страницей, что требует грамотного управления очередями задач.

Асинхронность и порядок выполнения

Puppeteer полностью основан на асинхронных операциях. Любой метод, который взаимодействует с браузером или страницей, возвращает Promise. Для корректного управления очередью задач критически важно строго соблюдать порядок вызовов через await или цепочки .then():

const puppeteer = require(&

(async () => {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();

    await page.goto('https://example.com');
    await page.click('#login-button');
    await page.type('#username', 'admin');
    await page.type('#password', 'password123');
    await page.click('#submit-button');

    await browser.close();
})();

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

Очередь задач и параллелизм

Для ускорения тестирования иногда требуется выполнять параллельные задачи, например, проверку нескольких страниц одновременно. Puppeteer позволяет создавать несколько экземпляров страниц (page) внутри одного браузера. Управление очередью здесь сводится к контролю количества одновременно выполняемых промисов.

const urls = ['https://example.com', 'https://example.org', 'https://example.net'];

const processPage = async (browser, url) => {
    const page = await browser.newPage();
    await page.goto(url);
    const title = await page.title();
    await page.close();
    return title;
};

(async () => {
    const browser = await puppeteer.launch();
    const results = await Promise.all(urls.map(url => processPage(browser, url)));
    console.log(results);
    await browser.close();
})();

Promise.all гарантирует, что все задачи будут запущены одновременно, а результатом станет массив их результатов. Для ограничения количества параллельных задач применяют семафоры или библиотеки очередей, например p-queue.

Создание пользовательских очередей

Для тестов, где важен строгий порядок или ограничение ресурсов, создают очереди с контролем конкарренции:

const PQueue = require('p-queue').default;
const queue = new PQueue({ concurrency: 2 }); // максимум 2 задачи одновременно

urls.forEach(url => {
    queue.add(async () => {
        const page = await browser.newPage();
        await page.goto(url);
        console.log(await page.title());
        await page.close();
    });
});

await queue.onIdle(); // ожидаем завершения всех задач

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

Управление событиями и задачами

Puppeteer поддерживает работу с событиями страницы: page.on(‘request’), page.on(‘response’), page.on(‘console’). Эти события часто интегрируют в очередь задач для тестирования асинхронного поведения страницы:

page.on('response', response => {
    if (response.url().includes('api/data')) {
        console.log(`Получен ответ от API: ${response.status()}`);
    }
});

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

Управление таймингом и ожидания

Очереди задач в Puppeteer тесно связаны с таймингом элементов. Методы page.waitForSelector, page.waitForTimeout, page.waitForResponse позволяют корректно синхронизировать выполнение действий:

await page.waitForSelector('#submit-button', { visible: true });
await page.click('#submit-button');
await page.waitForResponse(response => response.url().includes('/success') && response.status() === 200);

Правильное использование ожиданий предотвращает сбой тестов из-за несвоевременных действий, особенно при работе с динамическими страницами.

Практические рекомендации

  • Последовательные задачи: использовать await для гарантированного порядка выполнения.
  • Параллельные задачи: ограничивать количество одновременно выполняемых страниц или процессов.
  • Очереди с конкарренцией: применять библиотеки типа p-queue для сложных сценариев.
  • События и асинхронные ответы: обрабатывать через подписку на события и интегрировать в общую очередь задач.
  • Ожидания элементов и ответов: синхронизировать действия с состоянием страницы.

Эффективное управление очередями задач в Puppeteer позволяет создавать стабильные, воспроизводимые тесты, минимизируя влияние асинхронной природы браузера на результат.